Drupal 7 におけるフィールドのレンダリング<正攻法>

~ Rendering Drupal 7 fields (the right way) Computerminds 和訳 ~

結論

field_view_field() を使うべし!

解説

Drupal 7 では「エンティティ」という概念が導入されました。そしてそれらに関連付けられたフィールドの「格納、ロード、編集、レンダリング」を担う「フィールドAPI」という強力な機能が提供されています。コンテンツタイプの「フィールドの管理」、「表示管理」タブからの操作だけでも、これらのプロセスのほとんど全てをカバーすることができます。

エンティティとしての一連の処理の外で、特定のフィールドだけをレンダリングしたいという状況に出くわすことがしばしばあります。よくある例としては、ノードの投稿者名をサイドバーブロックに置きたい場合です。もちろん Panels や CCK Blocks モジュールを使えばこれは実現できますが、簡単なコーディングだけで済ませたい場合もあるでしょう。

このようなコードを見かけた(書いた!)ことはないでしょうか。:

// これは悪い例です。
$block['content'] = $node->field_name['und'][0]['safe_value'];

表示させたい値を得るのにノードオブジェクトを直接利用するのは、Drupal 6 ではかなり一般的でした。「 'safe_value' 」ならサニタイズ済みの安全な値のはずです。何がいけないのでしょう?理由をいくつかあげてみます。

  1. まず、「 'und' 」というのは、Drupal 7 ではフィールドの言語設定です(詳しくは Gabor Hojtsy 氏のこちらの記事を参照)。これを直に指定することは、マルチリンガル環境をも含めて考えるとうまくありません。
  2. テーマエンジンによるフィールドの正規のマークアップの恩恵を失わないためにも、フィールドの値を直で使用するべきではありません。
  3. [0]['safe_value'] と明示的にフィールドの最初の値を指定しています。これだとフィールドが複数の値をもつ場合に、何かしらのループ処理が必要になってきます。
  4. いくつかのフィールド(例えばノードリファレンスのような)には「 'safe_value' 」要素がありません。その場合はサニタイズを通していない「 'value' 」を使うことになり、これは安全ではありません。ノードリファレンスフィールドが安全でない値を含んでいるからというわけではなく(これらはただのノード ID です)、特に開発初心者にとっては、良くない習慣になってしまうからです。他のフィールドの「 'value' 」には、安全でない値が含まれているかもしれません。

うれしいことに、field_view_field() がすべて解決してくれます!

$output = field_view_field('node', $node, 'field_name');

この関数が返すのは、適切にサニタイズされ(#4をクリア)、要素全体を含んだ(#3をクリア)、適切な言語の(#1をクリア)、適切なマークアップを含んだ(#2をクリア)レンダリング配列です。使用中の言語でフィールドに有効な値がない場合は、サイトのデフォルトの言語が適用されます。すごい!これはまた、フォーマット設定や、ビューモードの指定を含む配列を、追加の引数として渡すことも出来ます。素晴らしいですね。!

オマケ

「そんな余計な事はしなくていいから、とにかく単一の値だけが欲しい。」という場合はどうでしょう?そんな時に使える2つの関数があります。ひとつは field_get_items() です。これは適切な言語設定のフィールドアイテムの配列を返します(必要なら、言語を特定することも出来ます)。ここから取得できるデータを使って、サーバーサイドの処理にそのまま利用することも出来ますし、たとえばイメージフィールドの alt テキストをどこか他の場所で使うといったような、想定外のようなことも出来ます。但し取り扱いには注意してください。特にユーザ入力の生データを扱う場合には、セキュリティーの脆弱性のリスクを回避するために、これらのデータを使用する前に必ず適切なサニタイズを通す必要があります。

もうひとつは field_view_value() です。これはフィールドの単一の値をレンダリングしたい場合に、適切にサニタイズされた値を含むレンダリング配列を返します。フォーマットの設定を渡すことも可能です。field_get_items() の結果の配列から、単一の値を取得したい場合に使えます。例:

$node = node_load($nid);
$field = field_get_items('node', $node, 'field_name');
$output = field_view_value('node', $node, 'field_name', $field[$delta]);

$delta はフィールドアイテムのキーです。単一の値のフィールドなら 0 となります。

ここで最後に興味深い例を紹介します。イメージフィールドを表示するのに、画像スタイルと、ノードへのリンクを設定します。これは field_view_value()field_view_field() で同じ結果になります。

$node = node_load($nid);
$image = field_get_items('node', $node, 'field_image');
$output = field_view_value('node', $node, 'field_image', $image[0], array(
  'type' => 'image',
  'settings' => array(
    'image_style' => 'thumbnail',
    'image_link' => 'content',
  ),
));

This Rocks.

この通り。「特定のフィールドをブロックに表示したい」というケースにフィールド API は見事に答えてくれました。クリーンでシンプルです。そしてレンダリング配列という形になっているので、テンプレートファイルでレンダリングが行われる時点まで、必要に応じて構造に手を加えることが出来ます。そして field_view_field()field_view_value() を使っているということは、既に適切なサニタイズが完了していることを意味します。鮮やか!

コア: 
Drupal7