Node Reference etc...

Events happening in the community are now at Drupal community events on www.drupal.org.
Onigiri's picture

以下の解説ビデオ
http://mustardseedmedia.com/podcast/episode37

を参考にして、location, movies, photosというコンテンツタイプを作成しました。
locationは各観光地の情報を掲載するページで、ノード参照によりmovies, photosのコンテンツを
表示しています。movies, photosの表示数はそれぞれのviewsの設定"Items to display"で
コントロールされています。

この表示数を超えた場合、pagerは利用せずに個別のページ(viewsで作成されたページ)へのリンクを作成し、
そこで一覧表示をするようにしたいと思っています。

各locationノードにはurl-aliasが設定されており、例えば example.com/location/tokyo/shibuya でアクセスできる
ようになっています。"tokyo"はtaxonomyのterm、"shibuya"は[title-raw]です。ここで、上記の個別のページを
example.com/location/tokyo/shibuya/movies
example.com/location/tokyo/shibuya/photos
に作成するよう試行錯誤していますが実現していません。

単にmoviesの一覧ページを作成するなら、viewsの設定から、フィルタでノードタイプをmoviesに絞って、
moviesのコンテンツをフィールドに追加すれば出来るのですが、それだとコンテンツタイプ:movies全てが対象となってしまい、
私の希望する『"location"の"shibuya"に関連づけられたmoviesの一覧』という表示になりません。
argumentsの設定により何とかするような印象("%"の扱いがカギではないか!?)を持っていますが、よくわかりません。

完成イメージとしては、
example.com/location/[term-name]/[title-row]/movies
example.com/location/[term-name]/[title-row]/photos
が自動で作成、というかページエラーにならずちゃんと一覧表示できるようになることです。

伝わりにくい説明と思いますが、アドバイス頂けないでしょうか。よろしくお願いします。

Comments

argument にterm nameとnode

dokumori's picture

argument にterm nameとnode titleを使い、page display の path をexample.com/location/%/%/photos に設定してみてはどうでしょう。

Viewsで taxonomy term を argument として受けとるとうまく動かない場合があるので、上記の方法でうまくいくかどうかは分かりませんが。

ちなみに、argument に term name や node title などを使った場合、値にスペースが入っていると、ブラウザによってスペースの処理が異なるため、それぞれのブラウザが異なる結果を返す場合があります。

進展アリ

Onigiri's picture

なるほど!argumentはそういう風に使うんですね。恥ずかしながらpathに"%1"とか"%2"を設定しており、
example.com/location/%1/%2/movies/tokyoみたいになってました。お教え頂いた方法を試してみたところ、
少し前進がありました。それと同時に自分の設定に問題があったことが判明しました。

当初は解説ビデオの通り、あるノードに他のノードのデータを引っ張ってくるということを実現したに過ぎず、
参照先の(ここではmovies, photos)コンテンツタイプにタクソノミーの設定をしていませんでした。
従って、node: type = moviesに一致するノードのtermを引数に利用しようとしても、そもそも存在しないため
上手くいっていませんでした。単純なことなのに...

またterm-nameのargumentへの利用ですが、ご指摘の通りスペースの扱いが怪しい雰囲気で、これを回避するために
Term IDを利用したところエラー無く表示できました。現時点では、

example.com/location/[tid]/movies
example.com/location/[tid]/photos

で各タームに属するmovies, photosの一覧を表示できるようになりました(ノード別のフィルタリングはまだです。
理由は後述)。しかしTermIDは数字なので、例えばexample.com/location/3/moviesという具合になってしまいます。
ちなみにターム名にはスペースが含まれるものの全てローマ字で統一してあり、pathautoでurl-aliasが作成される際に
ハイフンに変換されるので、このパス情報をargumentとして利用できないかなと思っています。

2番目の引数[title-row]は更に問題がありそうなので、手を付けていません。というのも、これは私の勘違いで、
この場合の[title-row]はmovies又はphotosのタイトルとなってしまい、これではコンテンツタイプ:locationのタイトルを
取得するはずがありません。参照元のノードタイトルを取得する方法は...?見当も付きません。

新しい完成イメージは
example.com/location/[catalias]/[node-path]/movies *[node-path]はlocationノードのもの
になるんでしょうか。徐々に問題点がクリアになってきた感じです。

dokumori's picture

ちなみにターム名にはスペースが含まれるものの全てローマ字で統一してあり、pathautoでurl-aliasが作成される際にハイフンに変換されるので、このパス情報をargumentとして利用できないかなと思っています。

これはできないかもしれません。
むしろ、/location/[tid]/[nid] というようなパスにしてしまい、それに対して alias を作成するほうがスッキリするのでは?aliasの自動生成にはカスタムモジュールが必要になると思いますが、あまり難しいものにはならないと思います。
追記:そんな風に書きつつ、できないかもしれないと思い始めました。その場合、上述のようなパスを作成し、それに対し hook_menu() で対応すべきだと思います。

2番目の引数[title-row]は更に問題がありそうなので、手を付けていません

参照元のノードタイトルを取得するには Relationships を使います。Relationships で参照元で使われている node reference のフィールドを選択し、'require this relationship'にチェックを入れてUpdateを押します。次にargument として node:title を追加し、'relationships' ドロップダウンで先に作成した relationship を指定します。

進展ナシ

Onigiri's picture

度々お答え頂き恐縮です。今度はRelationshipsの活用法を教えて頂き、これでviewsの意味不明だった項目が解消されました。
もちろん表面的な理解ですが。大変感謝しております。さて、

むしろ、/location/[tid]/[nid] というようなパスにしてしまい、それに対して alias を作成する

aliasの作成には至っていませんが、Relationshipsを活用して取得した参照元の[nid]と組み合わせて作成したパス、例えば
/location/3/2 で表示されるビューのページの動作は完璧ですね。これにaliasが被されば...しかし、ここから先は私には非常に高いハードルのようです。

上述のようなパスを作成し、それに対し hook_menu() で対応すべきだと思います。

このへんの記事を読んでも、私の場合どう適用すべきか分からず悩んでしまいます。なんせ知識が...
hook_menu()ではないですが、この記事を参考に単純なパスの書き換えを試みたところ上手くいきました。
しかし引数を用いたDBの操作となるとさっぱりです。

function custom_url_rewrite_outbound(&$path, &$options, $original_path) {
if (arg(0, $path) == 'location' && is_numeric(arg(1, $path)) && is_numeric(arg(2, $path))) {
$aliaspath = db_result(db_query("SELECT dst FROM {url_alias}...(略)

上記のようなコードを試してみましたが、まあダメですね。ところで、Relationshipsを追加するとフィールドで参照元のnode:pathが取得でき、
これはlocation/[catalias]/[node-path]という形式のため、[catalias],[node-path]をそれぞれargumentとすれば私の期待通りの表示となるよう思います。
ところがnode:pathの項目はフィールドでは利用できても、引数としては選択できません。何か理由があるんでしょうが、残念なところです。

「このへんの記事」はDrupal5

dokumori's picture

このへんの記事」はDrupal5 のものなので参考になりませんよ :)
Drupal6 では、menu は完全にルーターとして機能するので、コールバックを使う必要があります。以下のような感じになります

function local_menu() {
  $items = array();
  $items['location/%/%node'] = array(
    'title' => 'タイトル',
    'description' => '説明',
    'page callback' => 'local_display_result',
    'page arguments' => array(1, 2),
    'access arguments' => array('access content'),
  );

  return $items;

}

function local_display_result($tid, $node) {
  $view = views_get_view('[viewの名前]');
  $output = $view->preview('[display ID]', array($tid, $node->nid));
  //square bracket [] に入っている値は適宜変更してください。
  return $output;
}

こうしておけば、aliasの指定も可能になるはずです。以下のファンクションをhook_nodeapi()の実装の$op == 'save' あたりから呼べば、aliasの作成も自動化できると思います

function local_set_alias($tid, $nid) {
  $term = taxonomy_get_term($tid);
  $node = node_load($nid);
 
  $term_name = check_plain($term->name);
  $node_title = check_plain($node->title);
 
  path_set_alias("location/$tid/$nid", "location/$term_name/$node_title");

}

ちなみに、深夜3時すぎにビールを飲みながら検証せずに書いてるので、上記のコードがどこまで正しいかは保証できません。

あと、ロケーションが膨大な場合、path aliasをデータベースに格納するのは効率的に良い方法ではないかもしれません。

解決しました

Onigiri's picture

まず最初から最後までお世話になったdokumoriさんに感謝しなければいけません。ありがとうございました。
特別にコードまで提供して頂いておきながら申し上げにくいのですが、この度のaliasの作成に関してはrulesで自動化しました。
やはりビューのページパスを/location/[tid]/[nid]としたのが成功の要因で、的確なアドバイスを頂いたと思います。
上記設定によりシステム内部でのパスが有効になり、aliasの設定が可能となりました(認識が間違っていたらスミマセン)。
この段階で、システムパス:location/[tid]/[nid]にエイリアス:location/tokyo/shibuya/moviesを手動で作成可能なので、
あとはこの手順をrulesで条件付けして定義してやれば、自動化の完成というわけです。これはviews及びrulesで操作可能な
範囲での手法ですので、私のようなプログラミングの基礎もなっていない人間には安全なやり方だと思います。

今回私がやりたかったことは、引数により生成されるビューのページへのエイリアスの自動作成といったところでしょうか。
今後pathautoが対応してくれるといいですね。一応view aliasというモジュールもあるようですが、私のニーズとは異なるようでした。

この件を通じて多くのことを学ばせて頂いたと思います。またお世話になるかと思いますが、その時はどうか相手をしてやって下さい。

(『hook_nodeapi()の実装の$op == 'save' あたりから呼べば...』というのが理解できなかったのは内緒です。)

勘違いしていました。/location/[tid]/[ni

dokumori's picture

勘違いしていました。/location/[tid]/[nid] というviewsのページのパスに対して作れないのは、エイリアスではなく、メニューアイテムでした。それで以前、hook_menu()を実装して解決したのと混同していました。問題なくエイリアスが作れてよかったですね。

Rules でエイリアスの作成を自動化したのは良い解決法です。メジャーなモジュールの設定のみで機能の作成を行えば、Drupalを次のバージョンへアップグレードする際に、コードを書き直さなくて済むので。

日本 コミュニティ: Drupal Japan User Group

Group organizers

Group categories

Group notifications

This group offers an RSS feed. Or subscribe to these personalized, sitewide feeds: