Drupal 8のEntity API入門
Drupal 8のエンティティシステム
エンティティはメソッドを持つ型付きクラスです
| Generic methods |
$entity->id() |
| Entity type specific methods | $node->getTitle() |
Background
Entity SystemはDrupal 7の開発サイクルの終盤に、基本的なエンティティ読み込み標準とともに導入されました。追加されたentity.moduleはAPIをさらに拡張し、エンティティの保存・削除のサポートや、その他多くの改善を追加しました。
これらの改善のほとんどは現在Drupal 8に含まれています。エンティティの検証は独自のAPIで実行されるようになりました(たとえば、フォームではなくRESTで保存されたエンティティを検証できます)。
2つのバリエーション
コアのエンティティタイプには2つのバリエーションがあります。
設定エンティティ
Configuration Systemが使用されます。翻訳をサポートし、インストール用のカスタムデフォルト設定を提供できます。設定エンティティは共有の設定データベーステーブルに行として保存されます。
コンテンツエンティティ
カスタムフィールドと基本フィールドで構成され、リビジョンを持つことができ、翻訳をサポートします。コンテンツエンティティはカスタムデータベーステーブルに行として保存されます。テーブル名はエンティティの「id」と同じで、列はエンティティの「baseFieldDefinitions」メソッドで定義されます。
バンドル
バンドルはエンティティタイプの異なるバリエーションです。たとえば、ノードエンティティタイプの場合、バンドルは「記事」や「ページ」などのさまざまなノードタイプです。
通常、バンドルは設定エンティティで表されますが、contribモジュールには他のモデルもあります。たとえば、ノードの例では「article」ノードタイプ自体が設定エンティティです。設定には、設定やフィールドなど、コンテンツエンティティタイプ間の違いが保存されます。バンドル付きの新しいエンティティタイプを作成するとき、コンテンツの詳細と操作を管理するコンテンツエンティティと、コンテンツエンティティタイプ間の違いを処理する設定エンティティの両方を作成します。
アノテーション
新しいエンティティタイプを作成するときは、コアに組み込まれたアノテーションシステムを使用する必要があります。アノテーションはクラス上に置かれるdocblockコメントのように見えますが、Drupalコアによって解析・キャッシュされます。多くの点で、アノテーションはDrupal 7で使用されていたいくつかの古いスタイルに取って代わります。
アノテーションパーサー
アノテーションは、実行時にアノテーションエンジンによって読み取られ、解析されます。Drupal 8はDoctrineアノテーションパーサーを使用して、PHPが使用できるオブジェクトに変換します。
構文。 アノテーション構文は@ClassName()で囲まれ、主にkey/value pairsで構成され、中括弧を使用した配列を含めることができます。トップレベルのキーは引用符で囲んではいけませんが、配列キーは囲む必要があります。各key/value pairsは別々の行に置く必要があり、その行はコンマで終わる必要があります。特定の関数は値に対して実行できます。特に@Translation()関数です。
アノテーション構文の動作しない例:
/**
* @ContentEntityType(
* id = "my_entity_type_id",
* label = @Translation("My entity type label"),
* example_pair = "this_examples_value",
* example_array = {
* "array_key" = "array_value",
* "some_other_key" = "some_other_value",
* },
* )
*/
一般的なトップレベルのアノテーション
| Key = "Example Value" | 説明 | Entityバリアント |
| id = "node", |
エンティティタイプのマシン名。 |
Content & Config |
| label = @Translation("Node"), |
エンティティタイプの読みやすい名前。 |
Content & Config |
| admin_permission = "administer nodes", |
管理アクセスがエンティティタイプを設定・管理できるようにする権限。エンティティが「access」ハンドラを定義していない場合に必要です。 |
Content & Config |
| bundle_label = @Translation("Content type"), |
バンドルエンティティタイプのオプションの読みやすい名前。 |
Content |
| bundle_entity_type = "node_type", |
バンドル付きコンテンツエンティティを作成する場合、この値は設定エンティティの「id」である必要があります。この場合、「node_type」は設定エンティティです。 |
Content |
| base_table = "node", |
エンティティタイプのデータベーステーブル名。 |
Content |
| fieldable = TRUE, |
(boolean) このエンティティタイプをフィールドUIで拡張できるかどうか。 |
Content |
| field_ui_base_route = "entity.node_type.edit_form", | エンティティのフィールドUIが結び付けられているルートの名前。 | Content |
Handlers
ハンドラはエンティティのアノテーションで配列として定義されます。これらは、実行の特定の部分を他のPHPクラスにマッピングすることでエンティティをサポートします。これらのクラスは、割り当てられたエンティティ実行部分を「処理」します。
ストレージ - エンティティの読み込み、保存、削除を処理します。デフォルトでは、コンテンツエンティティはDrupal\Core\Entity\Sql\SqlContentEntityStorageを使用し、設定エンティティはDrupal\Core\Config\Entity\ConfigEntityStorageを使用します。エンティティの標準ストレージメソッドを拡張するために、ストレージハンドラを定義できます。たとえば、エンティティのリビジョンIDを収集したり、エンティティが持つ翻訳の数を判別したりする追加メソッドを提供したい場合などです。
例:"storage" = "Drupal\node\NodeStorage",
フォーム - エンティティハンドラのアノテーションには複数のフォームハンドラがあり、エンティティの追加・編集・削除フォームを他のPHPクラスにマッピングします。
例:
"form" = {
"add" = "Drupal\block\BlockForm",
"edit" = "Drupal\block\BlockForm",
"delete" = "Drupal\block\Form\BlockDeleteForm",
}
さらに、「add」フォームと「edit」フォームを個別に定義する代わりに、「default」フォームを定義して処理できます。「delete」フォームは、他のフォームとは別のクラスで処理されることがほぼ常です。これは、削除フォームが通常「確認フォーム」であり、ユーザーがエンティティを削除するかどうかを確認するだけだからです。
View builder - このハンドラは、エンドユーザーがエンティティを表示するときの出力を処理するクラスを提供します。たとえば、Drupal 8サイトでノードを訪れると、エンティティの出力はNodeViewBuilderクラスによって処理されます。
例:"view_builder" = "Drupal\node\NodeViewBuilder",
List builder - リストビルダークラスは、管理目的でエンティティのリストを処理します。このクラスは、エンティティの管理ページを訪れたときのヘッダー、行、操作の内容を定義します。たとえば、Drupalサイトの/admin/content URIを訪れると、テーブルの内容はNodeエンティティのリストビルダークラスによって提供されます。
例:"list_builder" = "Drupal\node\NodeListBuilder",
Route provider - オプションのハンドラで、実装されるとエンティティを管理するためのルートを生成します。このハンドラを実装すると、モジュールのrouting.ymlファイルで定義されたentityパスの必要性を置き換えることができます。route_providerは、エンティティに定義されたリンクと組み合わせて機能することに注意してください(下の「リンク」セクションの例を参照)。route_providerアノテーションは配列です。
例:
"route_provider" = {
"html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
}
Access - アクセスハンドラは、エンティティの権限を動的にチェックするために使用できます。これは、EntityAccessControlHandlerInterfaceを実装するクラスへのマッピングです。コアはこのインターフェースの実装としてEntityAccessControlHandlerを提供しますが、エンティティを確実に制御するには、このクラスを独自のクラスで拡張したくなるでしょう。
例:"access" = "NodeAccessControlHandler",
Views data - views_dataハンドラは、エンティティが提供するカスタムデータでViewsモジュールを拡張できるようにします。これは、エンティティのbaseFieldDefinitionsをビューのフィールドとして追加したり、エンティティのリレーションシップでテーブルを結合したり、ビューに関連するデータの変更を行ったりするためのものです。
例:"views_data" = "Drupal\node\NodeViewsData",
Storage schema - storage_schemaハンドラは、エンティティのデータベースストレージ設定をさらに変更するために実装できます。たとえば、追加のテーブルインデックスを追加する場合などです。
例:"storage_schema" = "Drupal\node\NodeStorageSchema",
Translation. 翻訳ハンドラは、エンティティのフォームが翻訳と対話する方法を変更するために使用できます。
例:"translation" = "Drupal\node\NodeTranslationHandler",
完全なhandlersの例:
Drupalコアは「そのまま」使用できるハンドラを提供しますが、多くの場合、エンティティをより細かく制御・カスタマイズするために、これらのクラスを独自のクラスで拡張したくなるでしょう。この例では、拡張できるコアクラスを使用した、より完全なハンドラアノテーションを示しています。
handlers = {
"view_builder" = "Drupal\Core\Entity\EntityViewBuilder",
"list_builder" = "Drupal\Core\Entity\EntityListBuilder",
"access" = "Drupal\Core\Entity\EntityAccessControlHandler",
"views_data" = "Drupal\views\EntityViewsData",
"storage" = "Drupal\Core\Entity\Sql\SqlContentEntityStorage",
"storage_schema" = "Drupal\Core\Entity\Sql\SqlContentEntityStorageSchema",
"translation" = "Drupal\content_translation\ContentTranslationHandler",
"form" = {
"default" = "Drupal\Core\Entity\ContentEntityForm",
"add" = "Drupal\Core\Entity\ContentEntityForm",
"edit" = "Drupal\Core\Entity\ContentEntityForm",
"delete" = "Drupal\Core\Entity\ContentEntityDeleteForm",
},
"route_provider" = {
"html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider",
},
},
リンク
リンクはエンティティのアノテーションで配列構文を使用して定義されます。リンクには特定のキーセットがあり、その値はエンティティタイプまたはそのタイプの個々のエンティティを管理できるURIです。これらのエンティティは、コンテンツと設定エンティティの両方で定義できます。
例:
id = "node",
handlers = {
"route_provider" = {
"html" = "Drupal\Core\Entity\Routing\AdminHtmlRouteProvider"
}
},
links = {
"canonical" = "/node/{node}",
"add-page" = "/node/add",
"add-form" = "/node/add/{node_type}",
"edit-form" = "/node/{node}/edit",
"delete-form" = "/node/{node}/delete",
"collection" = "/admin/content",
},
これはNodeモジュールから逐語的に引用したものではなく、単なる例であることに注意してください。
これらのリンクを作成しても、これらのURIのルートは自動的に作成されません。これらのリンクを利用できるようにするには、モジュールに独自のrouting.ymlファイルを実装するか、エンティティのアノテーションでroute_providerハンドラを使用する必要があります。
リンクとルートプロバイダー
上記のリンクは「route_provider」と連携して、次の名前付きルートをDrupalで利用できるようにします。
| リンクキー | ルート名 | ルートURIの例 | 説明 |
| canonical | entity.node.canonical | /node/1 | 特定のノードを表示 |
| add-page | entity.node.add_page | /node/add | 追加するノードを選択 |
| add-form | entity.node.add_form | /node/add/article | ノードを追加(特定のバンドル) |
| edit-form | entity.node.edit_form | /node/1/edit | 特定のノードのフォームを編集 |
| delete-form | entity.node.delete_form | /node/1/delete | 特定のノードのフォームを削除 |
| collection | entity.node.collection | /admin/content | すべてのノードをリストで表示 |
リンクの使用
これらのリンクは、エンティティのtoUrl()メソッドでアクセスできます:
$view_url_object = $entity->toUrl(); // Default is 'canonical'
$edit_url_string = $entity->toUrl('edit-form')->toString();
リンク:
- Entity API - 生成されたドキュメント。
- カスタムコンテンツエンティティの作成 - 非常にシンプルなカスタムエンティティ。
- Drupal 8でコンテンツentityタイプを作成する - ハンドラ、権限、ルーティング、リンクを含む拡張例。
- Drupal 8で設定エンティティタイプを作成する - ハンドラ、ルーティング、スキーマを含む拡張例。
- [External] Entity Type Walkthrough - 一般的なエンティティタイプの実践的なドキュメント