【Drupal】レンダリングAPIの概要
本記事は下記Drupal公式リファレンスを翻訳しています。
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!theme.api.php/group/theme_render/10
Drupal のテーマ システムの主な目的は、テーマに完全な制御を与えることです。 サイトの外観上 (HTTP から返されたマークアップを含む) リクエストとそのマークアップのスタイルに使用される CSS ファイルを定義してテーマに設定できます。テーマはマークアップを完全にカスタマイズできますが、モジュール開発者は避けるべきです。 ページ、ブロック、その他のユーザーに表示される出力の HTML マークアップを直接記述する モジュール内で、代わりに構造化された「レンダリング配列」を返します(「 以下に配列をレンダリングします )。 これにより、 サイトのさまざまな領域で同様の機能に使用されるマークアップは、 これにより、ユーザーが学習するユーザー インターフェイス パターンが少なくなります。
テーマとレンダリング API の詳細については、以下を参照してください。
配列をレンダリングする
レンダー API の中心構造はレンダー配列です。 レンダリングされるデータとプロパティを含む階層連想配列 データをどのようにレンダリングするかを説明します。 返されるレンダリング配列 Webブラウザなどに送信するマークアップを指定する機能による サービスは最終的にはへの呼び出しによってレンダリングされます。 \Drupal\Core\Render\RendererInterface::render ()、これは再帰的に実行されます。
必要に応じてレンダリング配列階層を作成し、テーマ システムを呼び出します。 実際のレンダリングを実行します。 関数またはメソッドが実際に返す必要がある場合 レンダリング配列ではなくレンダリングされた出力を使用する場合、ベスト プラクティスは次のとおりです。 レンダー配列を作成し、呼び出してレンダリングします。 \Drupal\Core\Render\RendererInterface::render () を実行し、その結果を返します。 マークアップを直接記述するのではなく。 のドキュメントを参照してください。
\Drupal\Core\Render\RendererInterface::render () の詳細については、 レンダリングプロセスを参照ください。
レンダー配列の階層内の各レベル(最も外側の配列を含む) には 1 つ以上の配列要素があります。
名前が「#」で始まる配列要素は次のとおりです。 「プロパティ」として知られ、他の名前を持つ配列要素は「子」です。 (階層の次のレベルを構成します); 子供たちの名前は 柔軟ですが、プロパティ名は Render API と レンダリングされる特定のタイプのデータ。 レンダリング配列の特殊なケースは次のとおりです。 form 配列。HTML フォームのフォーム要素を指定します。
フォームの詳細については、「フォーム生成」トピックを参照してください。
レンダリング配列 (階層のどのレベルでも) には通常、次のいずれかが含まれます。 次のプロパティが定義されています:
- #type : 配列に特定のデータとオプションが含まれていることを指定します。 「レンダリング要素」のタイプ (たとえば、HTML フォームの場合は「form」。 'textfield'、'submit'、HTML フォーム要素タイプの場合。 'table'、テーブルの場合 行、列、ヘッダーを含む)。 を参照してください レンダリング要素 詳細については、以下の 。 レンダリング要素のタイプ。
- #theme : 配列に特定のテーマを適用するデータが含まれていることを指定します。 テーマフック。 を実装することでテーマ フックを定義します モジュールは、 hook_theme () 。 データとオプションを提供するために使用される入力「変数」を指定します。 もし フック_テーマ ()実装は変数「foo」を指定し、レンダリングで 配列の場合は、プロパティ '#foo' を使用してこのデータを提供します。 モジュール ()を実装するには、 フック_テーマ デフォルトの実装も提供する必要があります。 それぞれのテーマフック。通常は Twig ファイル内にあります。 詳細については 利用可能なテーマフックを見つけるには、のドキュメントを参照してください。 フック_テーマ () と デフォルトのテーマ実装トピック。
- #markup : 配列が HTML マークアップを直接提供することを指定します。 そうでもなければ マークアップは段落タグでの説明など非常にシンプルですが、 通常は、代わりに #theme または #type を使用することをお勧めします。 マークアップをカスタマイズできます。 値が渡されることに注意してください \Drupal\Component\Utility\Xss::filterAdmin ()、既知の XSS を削除します。 ベクトルを使用しながら、XSS ではない HTML タグの許容リストを許可します ベクトル。 (たとえば、<script> と <style> は許可されません。) を参照してください。 \Drupal\Component\Utility\Xss 許可されるタグのリストについては、 ::$adminTags を参照してください。 もしも マークアップにこのリストにないタグが必要な場合は、実装できます。 テーマフックやアセットライブラリ。 または、キーを使用することもできます #allowed_tags を使用して、フィルタリングするタグを変更します。
- #plain_text : 配列が必要なテキストを提供することを指定します。 逃げた。 この値は #markup よりも優先されます。
- #allowed_tags : #markup が指定されている場合、これを使用してどのタグを変更することができます。 タグはマークアップ内で使用できます。 値はタグの配列です。 Xss::filter() は受け入れます。 #plain_text が設定されている場合、この値は無視されます。
使用例:
$output['admin_filtered_string'] = [
'#markup' => '<em>This is filtered using the admin tag list</em>',
];
$output['filtered_string'] = [
'#markup' => '<video><source src="v.webm" type="video/webm"></video>',
'#allowed_tags' => [
'video',
'source',
],
];
$output['escaped_string'] = [
'#plain_text' => '<em>This is escaped</em>',
];
JavaScript および CSS アセットは、レンダー配列で指定されます。 #attached プロパティ (「 レンダー配列でのライブラリのアタッチ 」を参照)。
$form['file_example_fid'] = array(
'#title' => t('Image'),
'#type' => 'managed_file',
'#description' => t('Upload your picture.'),
'#upload_location' => 'public://example_files/',
);
レンダラーがこの要素に遭遇すると、 #type => 'managed_file'
プロパティを指定すると、タイプのレンダリング要素として扱われます。 #managed_file
に対応します。 \Drupal\file\Element\ManagedFile
プラグイン。 レンダリング プロセス中に、プラグインは提供された定義を拡張して、 \Drupal\file\Element\ManagedFile
要素タイプ。 これには次のようなものが含まれます #pre_render
と #post_render
として始まったものを拡張するために使用されるコールバック #managed_file
要素をいくつかの要素に分割します。これには、ファイル アップロード フィールド、送信ボタン、以前にアップロードされたファイルが存在する場合はそのプレビューが含まれます。 利点は、これらのデフォルトの動作方法を変更したり、すべてをそのままにして、毎回最初からコードを作成することなく、標準の AJAX 対応ファイル アップロード ウィジェットを取得したりできることです。
レンダリング要素
レンダリング要素は Drupal コアとモジュールによって定義されます。 主な方法は、 レンダー要素の定義とは、レンダー要素プラグインを作成することです。 がある 2 種類のレンダリング要素プラグイン:
- 汎用要素 : 汎用レンダリング要素プラグインの実装 \Drupal\Core\Render\Element\ElementInterface には、次の注釈が付けられます \Drupal\Core\Render\Annotation\RenderElement アノテーション、プラグインに入れる namespace 要素を拡張し、通常は \Drupal\Core\Render\Element\RenderElement 基本クラス。
- フォーム入力要素 : フォーム入力要素を表す要素をレンダリングします。 を実装し \Drupal\Core\Render\Element\FormElementInterface 、注釈が付けられます を使用して \Drupal\Core\Render\Annotation\FormElement アノテーション プラグインに移動します namespace 要素を拡張し、通常は \Drupal\Core\Render\Element\FormElement 基本クラス。
を参照してください。 プラグイン API のトピック 一般的な情報については、 プラグインについて。 RenderElement または FormElement を使用してクラスを検索できます 注釈を使用して、どのレンダリング要素が使用可能であるかを確認します。 APIリファレンス など サイト ( https://api.drupal.org ) は、既存のすべてのリストを生成します これらのクラスの要素。 APIナビゲーションでElementsリンクを探します。 ブロック。
モジュールは、要素プラグインを定義することでレンダリング要素を定義できます。
レンダリングの仕組み
たとえば、レンダー配列を作成するときは、次のようなものを記述することができます。
$form['file_example_fid'] = array(
'#title' => t('Image'),
'#type' => 'managed_file',
'#description' => t('Upload your picture.'),
'#upload_location' => 'public://example_files/',
);
レンダラーがこの要素に遭遇すると、 #type => 'managed_file'
プロパティを指定すると、タイプのレンダリング要素として扱われます。 #managed_file
に対応します。 \Drupal\file\Element\ManagedFile
プラグイン。 レンダリング プロセス中に、プラグインは提供された定義を拡張して、 \Drupal\file\Element\ManagedFile
要素タイプ。 これには次のようなものが含まれます #pre_render
と #post_render
として始まったものを拡張するために使用されるコールバック #managed_file
要素をいくつかの要素に分割します。これには、ファイル アップロード フィールド、送信ボタン、以前にアップロードされたファイルが存在する場合はそのプレビューが含まれます。 利点は、これらのデフォルトの動作方法を変更したり、すべてをそのままにして、毎回最初からコードを作成することなく、標準の AJAX 対応ファイル アップロード ウィジェットを取得したりできることです。
画像
を見てみましょう \Drupal\file\Element\ManagedFile
これを実際に見てみましょう。 の \Drupal\file\Element\ManagedFile::getInfo()
と \Drupal\file\Element\ManagedFile::processManagedFile()
は特に有益です。
このパターンは、他の複雑な表示要素にも同様に適用できます。 例としては次のものが挙げられます。
- 5 つ星の投票ウィジェット
- データの配列を HTML テーブルにフォーマットできるテーブル要素
- ユーザーが構成したコンテンツのリストに動的に置き換えられるプレースホルダー
レンダリング要素は、複雑なロジックを強力にカプセル化します。 一度理解すると、覚えて再利用しやすいショートカットになります。
キャッシング
Drupal レンダリング プロセスには、いつでもレンダリングされた出力をキャッシュする機能があります。 レンダー配列階層内のレベル。 これにより、高価な計算が可能になります。 頻繁に実行されず、ページの読み込みが高速化されます。 を参照してください。 キャッシュ API トピックを参照してください。 キャッシュに関する一般的な情報については、 システム。
キャッシュを可能にするには、次の情報が必要です。 現在:
- キャッシュ キー : レンダー配列のキャッシュ可能な部分の識別子。 これらは レンダー配列の一部に対して作成および追加する必要があります。 レンダリング プロセスで高価な計算が必要になります。
- キャッシュ コンテキスト : ユーザー ロールやユーザー ロールなど、レンダリングに影響を与える可能性のあるコンテキスト 言語。 コンテキストが指定されていない場合は、レンダリング配列が どのような文脈によっても変わりません。
- キャッシュ タグ : レンダリングが依存するデータのタグ。 個々のノードまたはユーザー アカウント、つまりこれらが変更されたときにキャッシュが変更されるようにする 自動的に無効化することができます。 データがエンティティで構成されている場合、 使用して生成できます \Drupal\Core\Entity\EntityInterface::getCacheTags () を 適切なタグ。 構成オブジェクトにも同様のメソッドがあります。
- Cache max-age : レンダー配列をキャッシュできる最大期間。 デフォルトは \Drupal\Core\Cache\Cache::PERMANENT (永続的にキャッシュ可能) です。
キャッシュ情報は、レンダー配列の #cache プロパティで提供されます。 の このプロパティでは、常にキャッシュ コンテキスト、タグ、および最大有効期間を指定します。 レンダリング配列はコンテキストによって異なり、変更可能なデータに依存するか、依存します それぞれ、限られた期間のみ有効な情報に関するものです。 キャッシュキー キャッシュする必要があるレンダー配列の部分にのみ設定する必要があります。 コンテキストは現在のリクエストの値に自動的に置き換えられます (現在の言語など) をキーと組み合わせてキャッシュ ID を形成します。 キャッシュ コンテキスト、タグ、および max-age はレンダー配列に伝播されます。 レンダー配列セクションを含むキャッシュ可能性を決定するための階層。
#cache プロパティに含まれる内容の例を次に示します。
'#cache' => [
'keys' => ['entity_view', 'node', $node->id()],
'contexts' => ['languages'],
'tags' => $node->getCacheTags(),
'max-age' => Cache::PERMANENT,
],
応答レベルでは、X-Drupal-Cache-Contexts と X-Drupal-Cache-Tags ヘッダー。
を参照してください 、https://www.drupal.org/developing/api/8/render/arrays/cacheability 詳細については 。 詳細。
レンダー配列にライブラリをアタッチする
ライブラリ、JavaScript 設定、フィード、HTML <head> タグおよび HTML <head> リンク #attached プロパティを使用して要素に添付されます。 #attached プロパティ は連想配列であり、キーは添付ファイルのタイプ、 値は添付データです。
#attached プロパティは、HTTP ヘッダーと 応答ステータスコード。
#attached プロパティを使用すると、アセット ライブラリ (次のものが含まれる場合があります) をロードできます。 CSSアセット、JavaScriptアセット、JavaScript設定アセット)、JavaScript 設定、フィード、HTML <head> タグ、および HTML <head> リンク。 の配列を指定します type => value のペア。タイプ (ほとんどの場合、ライブラリの場合は「library」、または 'drupalSettings' — JavaScript 設定用) これらの応答レベルを添付します 価値観。 例:
$build['#attached']['library'][] = 'core/jquery';
$build['#attached']['drupalSettings']['foo'] = 'bar';
$build['#attached']['feed'][] = [
$url,
$this
->t('Feed title'),
];
を参照してください \Drupal\Core\Render\AttachmentsResponseProcessorInterface 追加情報については、 。 情報。
()を参照してください 、 \Drupal\Core\Asset\LibraryDiscoveryParser::parseLibraryInfo 詳細については 。 ライブラリを定義する方法に関する情報。
レンダリング配列内のプレースホルダー
レンダリング配列にはプレースホルダー メカニズムがあり、データを追加するために使用できます。 レンダリング プロセスの後半でレンダリング配列に追加されます。 これは同様の方法で機能します への方法 \Drupal\Component\Render\FormattableMarkup::placeholderFormat () 、 要素の #markup プロパティに入るテキストは、 レンダリング プロセスの最後で、プレースホルダーから置換を取得します。 #attached プロパティの「placeholders」要素に保存されます。
たとえば、残りのレンダリング プロセスが完了した後、 レンダリング配列には以下が含まれます:
$build['my_element'] = [
'#markup' => 'Something about @foo',
'#attached' => [
'placeholders' => [
'@foo' => ['#markup' => 'replacement'],
],
];
その場合、#markup には「置換に関する何か」が含まれることになります。
各プレースホルダー値はそれ自体がレンダリング配列である必要があることに注意してください。 そうなる レンダリングされ、レンダリング中に生成されたキャッシュ タグが マークアップのタグをキャッシュします。
レンダーパイプライン
「レンダー パイプライン」という用語は、Drupal が実行するために使用するプロセスを指します。 モジュールによって提供される情報を取得し、それを応答にレンダリングします。 見る https://www.drupal.org/developing/api/8/render 詳細については、 プロセス。 ルーティングの概念の背景については、を参照してください。 ルーティング API。
実際には、複数のレンダリング パイプラインがあります。
- Drupal は常に Symfony レンダー パイプラインを使用します。 見る https://symfony.com/doc/3.4/components/http_kernel.html
- Symfony レンダー パイプライン内には Drupal レンダー パイプラインがあります。 レンダリング配列を返すコントローラーを処理します。 (Symfony のレンダリング パイプラインは、Response オブジェクトの処理方法のみを知っています。 このパイプライン レンダー配列を Response オブジェクトに変換します。)これらのレンダー配列は メイン コンテンツとみなされ、複数の形式でレンダリングできます。 HTML、Ajax、ダイアログ、モーダル。 モジュールは、次のようにして、より多くの形式のサポートを追加できます。 タグ付けされたサービスであるメイン コンテンツ レンダラーの実装 「render.main_content_renderer」。
- 最後に、HTML メイン コンテンツ レンダラー内に別のパイプラインがあります。 メインコンテンツを含むページを複数の形式でレンダリングできるようにするため 方法: まったく装飾を行わない (メインコンテンツを表示するページのみ) かブロック (領域を含むページ。メインの周囲の領域にブロックが配置されています) コンテンツ)。 モジュールはページを実装することで追加のオプションを提供できます バリアント。次の注釈が付けられたプラグインです。 \Drupal\Core\Display\Annotation\PageDisplayVariant 。
コントローラーが \Symfony\Component\HttpFoundation\Response を返すルート オブジェクトは Symfony レンダー パイプラインによって完全に処理されます。
コントローラーが「メインコンテンツ」をレンダー配列として返すルートは、 複数の形式 (HTML、JSON など) および/または「装飾された」形式でリクエストされます。 上記のような方法で。
参照
フックテーマ ()
\Symfony\Component\HttpKernel\KernelEvents::VIEW
\Drupal\Core\EventSubscriber\MainContentViewSubscriber
\Drupal\Core\Render\MainContent\MainContentRendererInterface
\Drupal\Core\Render\MainContent\HtmlRenderer
\Drupal\Core\Render\RenderEvents::SELECT_PAGE_DISPLAY_VARIANT
\Drupal\Core\Render\Plugin\DisplayVariant\SimplePageVariant
\Drupal\block\Plugin\DisplayVariant\BlockPageVariant
\Drupal\Core\Render\BareHtmlPageRenderer
この記事に関するご質問やご意見などございましたらお問い合わせフォームからお気軽にご連絡ください。