9.10. Drupal Fields API。データベース内の Drupal フィールド。

この記事では、Drupal のフィールドがどう動作するか、なぜ必要なのか、そしてフィールドが Drupal でのサイト開発をどう素早くするのに役立つかを理解します。
前の記事ですでにフィールドを扱いました:
7.5. bootstrap カラムでサービスブロックを組む
それでは、どう動作するか見ていきましょう。Article タイプのコンテンツフィールドの編集に移動し、新しい Link タイプのフィールドを追加しましょう:
/admin/structure/types/manage/article/fields

新しい記事を作成すると、2 つの入力――URL とテキストリンク――が表示されます:

管理画面を通じて新しいフィールドを作成するたびに、データベースに 2 つのテーブルが作成されます:
{entity_type}__{field_name}
{entity_type}_revision__{field_name}
Drupal はリビジョンをサポートしているので、すべてのデータは少なくとも 1 回複製されます。というのも、唯一のリビジョンがあなたの記事の現在のリビジョンだからです。したがって、フィールドと Drupal Fields API 全体は、データベースの操作を簡素化するために必要です。管理画面を通じてフィールドを作成するだけで、drupal がすでにデータベースにテーブルを作成します。
MySQL テーブルの名前から、同じフィールドが 1 つのタイプのエンティティに使えることが分かるはずです。ですから例えば、すでに存在する Link フィールドを Basic Page タイプのコンテンツで使えます:
/admin/structure/types/manage/page/fields/add-field

しかし、ブロックに Link フィールドを作成したい場合は、新しいフィールドを作成する必要があります。同じフィールドを異なるタイプの Entity で使うことはできません。Basic Block タイプ用の Link フィールドを作成しましょう:
/admin/structure/block/block-content/manage/basic/fields/add-field
ご覧のとおり、フィールドを作成する際、既存のフィールドから Link フィールドを選ぶ選択肢はありません。というのも、Block と Node は異なるタイプの Entity だからです。
そして、ノードの場合と同様に、ブロック用の Link フィールドのデータを保存する 2 つのテーブルができます:

block_content_revision__field_link と block_content__field_link。
次に、drupal が異なるバンドルのノードに対して同じフィールドのデータをどう保存するかを理解しましょう。Article ノードタイプ用に Link フィールドを作成し、次にこのフィールドを Basic Page ノードタイプで再利用しました。便宜上、サイトの構成をフォルダーにアップロードしてファイルを見るのが最善ですが、adminer や phpmyadmin を通じて config テーブルで必要な構成を見つけることもできます:

link という単語を含むすべての構成を検索すると:
SELECT * FROM `config` WHERE CONVERT(`name` USING utf8mb4) LIKE '%link%' LIMIT 50
私たちの field_link フィールドに関して、次の構成が見つかります:
field.field.block.block_content.basic.field_link
field.field.node.article.field_link
field.field.node.page.field_link
field.storage.block_content.field_link
field.storage.node.field_link
各 Entity タイプについて、各フィールドは独自の Field Storage 構成を作成します。この構成は、テーブル {entity_type}__{field_name}、{entity_type}_revision__{field_name} にデータをどう保存するかに応答します。私たちの場合、これらは block_content_field_link、block_content_revision_field_link、node__field_link、node_revision__field_link テーブルです。次に、Link モジュールがデータをどう保存するかを調べます。Link フィールドの Field Storage 構成を開いてみましょう:
uuid: dba847ef-f4d6-4462-a2ee-f642a007fca6
langcode: en
status: true
dependencies:
module:
- block_content
- link
id: block_content.field_link
field_name: field_link
entity_type: block_content
type: link
settings: { }
module: link
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
Field Storage 構成に正確に何が保存されているかが明確になるように、これらの各行を見てみましょう。
uuid: dba847ef-f4d6-4462-a2ee-f642a007fca6
ここには、各 Config に固有の Config ID が保存されています。ローカルでフィールドを作成して構成をアップロードした場合、staging で手動でフィールドを作成する必要はありません。フィールドは自動的に作成されます。フィールドを削除してローカルで構成を削除すると、staging にインポートした後、すべてのデータも削除されます。したがって、staging でフィールドを作成した場合は、構成をアップロードして git に追加し、変更を無駄にしないようにしてください。
langcode: en
多言語サイトでは、異なる言語の異なるバージョンのノードに対して、フィールドのテーブルにすべての言語のすべてのデータが保存され、特定のデータがどの言語を使うかを示します:

私は同じ言語を使っているので、構成のデフォルト言語も同じです。
status: true
すべての構成エンティティに共通するのは、このエンティティが有効か無効かを示す status フィールドです。Field Storage 構成は drupal で作成された構成エンティティを使います。FieldStorageConfig クラスを参照してください。これは ConfigEntityBase から継承されています:
https://api.drupal.org/api/drupal/core!modules!field!src!Entity!
dependencies:
module:
- block_content
- link
アドオンモジュールへの依存です。ブロックで Link フィールドを使ったので、必須の Block content モジュールがあります。
id: block_content.field_link
私たちの構成の一意な名前です。
field_name: field_link
作成したフィールドのマシン名は Drupal が使います。ですから、このマシン名は例えばノードオブジェクトにアクセスする際に使えます $node->field_link->uri。Entity フィールドをどう参照するかは、次の記事で詳しく理解します。
Entity_type: block_content
私たちの Field Storage 構成がどのタイプの Entity か
type: link
Drupal のフィールドタイプです。独自のタイプのフィールドを作成しますが、今は、このフィールドタイプ link が Link モジュールによって作成されることだけを知っておく必要があります。次のクラスを見られます
core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
これが私たちの構成で使われています。
settings: { }
ここにはフィールドタイプの設定を保存します。今は空ですが、例えば body フィールドには、ティーザーを表示するかどうかの設定があります:
config/sync/field.field.block_content.basic.body.yml
settings:
display_summary: false
module: link
link フィールドタイプを持つモジュールです。今はモジュール名とフィールドタイプ link が同じですが、異なる場合もあります。例えば、1 つのモジュールで複数のタイプのフィールドを実装できます。DateTime モジュールでそうされているように:
core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
locked: false
フィールドが編集可能かどうかを示します。これはフィールドの設定を意味します。少し前、例えば Commerce モジュールの Billing Information と Shipping Information フィールドはブロックされていました。というのも、配送と税計算を使う際にこのフィールドの存在が必須だったからです。
cardinality: 1
このフィールドに入力できる 1 つの Entity に対する値の数です。1 つの値を選びましたが、ここでは別の数、2、3、5 などかもしれません。無制限の数の値には cardinality: -1 が使われます。
translatable: true
このフィールドが他の言語に翻訳可能かどうか
indexes: { }
このフィールドでのより良い検索のための追加の SQL インデックスです。通常、データベースクエリの構成と最適化に必要です。
persist_with_no_fields: false
すべての Entity からフィールドが削除された場合に Field Storage を削除するかどうかを示します。例えば、Article と Basic Page からフィールドを削除しても、Field Storage は削除されません。
custom_storage: false
Custom storage は、フィールドデータを保存するための特別なテーブルを持ち、{entity_type}__{field_name} ではないことを意味します。このようなものは使いませんが、他のシステムとの統合には便利なことがあります。
それでは、link フィールドタイプのファイルを開いてみましょう:
core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
そして、このフィールドがデータベースにどんなデータを保存するか見てみましょう。これは propertyDefinitions() メソッドで見られます:
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['uri'] = DataDefinition::create('uri')
->setLabel(t('URI'));
$properties['title'] = DataDefinition::create('string')
->setLabel(t('Link text'));
$properties['options'] = MapDataDefinition::create()
->setLabel(t('Options'));
return $properties;
}
ご覧のとおり、URI、Title、Options のデータを保存します。node__field_link テーブルを開くと、同じフィールドが見られます:

これで Drupal の Fields API のトピックにたどり着きました。LinkItem クラスを持つ PHP ファイルの中で、モジュールを通じてフィールドタイプを作成します。これにより、Entity 用のフィールドを作成でき、次にそれを使ってデータを入力し、このデータをデータベースに保存できます。これがデータ入力のケースです。Fields API はまた、私たちのフィールドのデータ入力と出力のフォームも構成します。
Article と Basic Page コンテンツタイプにフィールドを作成した時点に戻りましょう。Node の Field Storage 用の構成ファイルは 1 つ field.storage.node.field_link.yml ですが、フィールドを作成する際、Entity の各バンドルにもう 1 つ構成ファイルを作成します。ですから例えば、今はフィールドに 3 つの構成ファイルがあります
field.field.node.article.field_link.yml
field.field.node.page.field_link.yml
field.field.block.block_content.basic.field_link.yml
これらの構成は、フィールド設定フォームのデータを保存します:

このようにして、異なるバンドルに対して異なる方法でフィールドのデータ入力フォームをカスタマイズできます。バンドル内の 1 つ 1 つのフィールド構成は Drupal では Field Instance と呼ばれるので、まず各バンドルで個別に Field Instance で使える Field Storage フィールドを作成します。Drupal 8 では、Drupal 7 とは異なり、Field Instance を扱う関数はもうなく、インスタンスを扱う機能は CRUD API に移行しました:
https://www.drupal.org/node/2054619
コードを通じてフィールドを扱う例は、公式ドキュメントで見られます:
https://www.drupal.org/node/2012896
私たちは、フィールドデータのデータベースへの保存に関する Fields API の部分だけを見ました。次のいくつかのレッスンでは、Fields API がデータ入力とフィールドデータ出力をどう扱うかを見て、また独自の本格的なフィールドタイプを作ります。