エンティティタイプクラスを変更するにはどうすればよいですか?


9

Drupal 8では、エンティティを次のようにロードできます。

$node = \Drupal::entityManager()->getStorage('node')->load(123);

これによりエンティティ定義が検索され、ノードDrupal \ node \ Entity \ Nodeによって定義されていることがわかります。そのため(おそらくDrupal \ node \ NodeStorageは新しいDrupal \ node \ Entity \ Nodeインスタンスをインスタンス化します。

私が達成したいのは、Drupal \ node \ Entity \ Nodeをサブクラス化し、適切なときにこのサブクラスをインスタンス化できるようにすることです。たとえば、ノードバンドルの記事がある場合、クラスがあります。

namespace Drupal\my_module\Entity\Article;
class Article extends Drupal\node\Entity\Node {
}

そして私は電話します:

$node = \Drupal::entityManager()->getStorage('node_article')->load(123);

そして、戻り値は私のArticleサブクラスになります。

これを実現するには、新しいエンティティタイプを作成し、それを別の既存のエンティティ定義に関連付けます。たとえば、ノードと記事の例は次のクラスになります。

namespace Drupal\my_module\Entity;
use Drupal\node\Entity\Node;
/**
 * @ContentEntityType(
 *   id = "node_article",
 *   label = @Translation("Content"),
 *   bundle_label = @Translation("Content type"),
 *   handlers = {
 *     "storage" = "Drupal\node\NodeStorage",
 *     "storage_schema" = "Drupal\node\NodeStorageSchema",
 *     "view_builder" = "Drupal\node\NodeViewBuilder",
 *     "access" = "Drupal\node\NodeAccessControlHandler",
 *     "views_data" = "Drupal\node\NodeViewsData",
 *     "form" = {
 *       "default" = "Drupal\node\NodeForm",
 *       "delete" = "Drupal\node\Form\NodeDeleteForm",
 *       "edit" = "Drupal\node\NodeForm"
 *     },
 *     "route_provider" = {
 *       "html" = "Drupal\node\Entity\NodeRouteProvider",
 *     },
 *     "list_builder" = "Drupal\node\NodeListBuilder",
 *     "translation" = "Drupal\node\NodeTranslationHandler"
 *   },
 *   base_table = "node",
 *   data_table = "node_field_data",
 *   revision_table = "node_revision",
 *   revision_data_table = "node_field_revision",
 *   translatable = TRUE,
 *   list_cache_contexts = { "user.node_grants:view" },
 *   entity_keys = {
 *     "id" = "nid",
 *     "revision" = "vid",
 *     "bundle" = "type",
 *     "label" = "title",
 *     "langcode" = "langcode",
 *     "uuid" = "uuid",
 *     "status" = "status",
 *     "uid" = "uid",
 *   },
 *   bundle_entity_type = "node_type",
 *   field_ui_base_route = "entity.node_type.edit_form",
 *   common_reference_target = TRUE,
 *   permission_granularity = "bundle",
 *   links = {
 *     "canonical" = "/node/{node}",
 *     "delete-form" = "/node/{node}/delete",
 *     "edit-form" = "/node/{node}/edit",
 *     "version-history" = "/node/{node}/revisions",
 *     "revision" = "/node/{node}/revisions/{node_revision}/view",
 *   }
 * )
 */
class Article extends Node { }

// Results my Article sub type.
$node = \Drupal::entityManager()->getStorage('node_article')->load(123);

これは(私が見る限り)正常に機能します。ただし、においがします。これは新しいエンティティタイプを追加しますが、これは真実ではなく、将来、他の問題を引き起こす可能性があります。

エンティティをロードするとそのクラスのオブジェクトが返されるように、エンティティバンドルのサブクラスを定義するにはどうすればよいですか?


1
バンドルごとに異なるエンティティクラスを提供できるかどうかはわかりません。を使用hook_entity_type_alter()して変更をより明確に行うことができますが、それを特定のバンドルに制限する方法はわかりません
Clive

ありがとうクライヴ-それは調査する有望なフックに見えます!
itarato

回答:


10

拡張するモジュールに新しいクラスを作成します\Drupal\node\Entity\Node

use Drupal\node\Entity\Node as BaseNode;

class MyNode extends BaseNode {
}

実装しhook_entity_type_build()ます。

use Drupal\Core\Entity\EntityTypeInterface;

/**
 * @param EntityTypeInterface[] $entity_types
 */
function my_module_entity_type_build(&$entity_types) {
  if (isset($entity_types['node'])) {
    $entity_types['node']->setClass('Drupal\my_module\Entity\MyNode');
  }
}

キャッシュを再構築することを忘れないでください。

エンティティタイプマネージャーサービスとノードストレージを介してノードをロードする場合、正常に動作します。Drupal\node\Entity\Node::load($nid)このload()関数は、Entityクラスから拡張されたクラスによって提供されるエンティティタイプマネージャーサービス呼び出しの静的ラッパーにすぎないという事実のおかげで、使用した場合でも機能しますNode

// Part of Entity class for reference
abstract class Entity implements EntityInterface {
  /**
   * Loads an entity.
   *
   * @param mixed $id
   *   The id of the entity to load.
   *
   * @return static
   *   The entity object or NULL if there is no entity with the given ID.
   */
  public static function load($id) {
    $entity_manager = \Drupal::entityManager();
    return $entity_manager->getStorage($entity_manager->getEntityTypeFromClass(get_called_class()))->load($id);
  }
}

これは間もなく削除されるentity_load_multiple()機能でも正常に機能するため、ノードをロードするためのすべての標準的な使用例をカバーしていると思います。

もちろん、モジュールがこれを実行し、別のモジュールが同じことを実行する場合、問題が発生しますが、これは一般的なシナリオではなく、非常に特定のユースケースでのみ意味があります。


2
申し訳ありませんが、いいえ:)質問は、バンドルごとに異なるクラスを持つことでした。エンティティタイプノードのすべてのバンドルのクラスを変更します。それは同じではありません。
Berdir 2016年

@Berdir、ノードのための実体ストレージがあまりにもそれの負荷方法はバンドルクラスごとにそれらを生産するためにオーバーライドすることができることを、基本的には、1つの巨大な頭痛の種はどれ延長されなければならないことをバンドル手段ごとのあなたの権利:( ...持つクラス。。
SiliconMind 2016年

1
うん。drupal.org/node/2570593は、私が参照した問題の1つですが、私の回答で実際にリンクするのを忘れていました。
Berdir

カスタムクラスを設定するためにhook_entity_type_alterを実装しました。それも動作します。
Yenya

このメソッドを試行すると、「Drupal \ Component \ Plugin \ Exception \ PluginNotFoundException: "node" entity type does not exist。」が表示されます。メッセージ。.moduleファイルでablecore_entity_type_build関数を使用しています。AbleNode.phpは/ src / Entity / AbleNode /フォルダーにあります
Matt

2

同じ問題が発生し、プラグインシステムを介してDrupalエンティティのエンティティタイプクラスを変更するモジュールを作成することにしました。現在NodeUserFileエンティティクラスの変更をサポートしています。変更する場合Nodeentitiyを、あなたはノードバンドルあたりの型クラスを変更することができます。

例については、モジュールの説明を確認してください。

https://www.drupal.org/project/entity_type_class

モジュールは、hook_entity_type_alter()を使用して、プラグインアノテーションで提供するエンティティにハンドラークラスを設定します。



-1

これは古い質問ですが、本当の答えは次のとおりです。

バンドル間で異なる動作が必要な場合は、異なるバンドルではなく、異なるエンティティタイプを使用する必要があります。

カスタムコンテンツエンティティは、D8のファーストクラスの市民です。実際、ノードのレベルに新しいカスタムコンテンツエンティティを取得するのに約30分かかると見積もられています(これは、フォームUIを追加して、見栄えの良いサイドパネルとエイリアス/リビジョンフィールドを取得することになります)。翻訳ページの追加は含まれていませんが、それだけではありません。

まだご覧になっていない場合は、Drupalコンソールのgenerate:custom:entity機能をご覧ください。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.