如何更改实体类型类?


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子类。

我可以通过创建一个新的实体类型并将其连接回另一个现有的实体定义来实现这一点,例如node-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()做出改变更干净,但我不知道你会如何限制到特定的捆绑
克莱夫

谢谢克莱夫-这看起来很有希望进行调查!
itarato

Answers:


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()函数只是EntityNode类扩展的类提供的实体类型管理器服务调用的静态包装,因此即使在您仅使用它时,它也可以工作。

// 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,你的权利:( ......具有每束的手段班,对节点的实体存储就必须得这样它的负载方法可以重写生产这些每捆类扩展这基本上是一个巨大的头痛。
SiliconMind

1
是的 drupal.org/node/2570593是我提到的问题之一,但是却忘记了在我的答案中实际链接到的问题。
贝尔迪尔

我已经实现hook_entity_type_alter来设置自定义类。它也可以。
Yenya

当我尝试这种方法时,我得到一个'Drupal \ Component \ Plugin \ Exception \ PluginNotFoundException:“节点”实体类型不存在。信息。我在我的.module文件中使用enabledcore_entity_type_build函数。我在/ src / Entity / AbleNode /文件夹中有我的AbleNode.php
Matt



-1

这是一个老问题,但真正的答案应该是:

如果需要在捆绑软件中使用不同的行为,则应该使用不同的实体类型,而不是不同的捆绑软件。

自定义内容实体是D8中的一等公民。实际上,我们估计将一个新的自定义内容实体提升到该节点所需的级别大约需要30分钟(实际上归结为添加Form UI以获取漂亮的侧面板以及别名/修订字段。)不包括添加翻译页面,但这还不止这些。

如果您还没看过,请看一下Drupal Console的generate:custom:entity功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.