Как я могу изменить класс типа сущности?

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);

Это прекрасно работает (насколько я вижу); однако пахнет. Он добавляет новый тип сущности, который не соответствует действительности и может вызвать другие проблемы в будущем.

Как определить подкласс для пакета сущностей, чтобы при загрузке сущности возвращался объект этого класса?

itarato
источник
1
Я не уверен, что вы можете предоставить другой класс сущности для пакета; вы можете использовать это, hook_entity_type_alter()чтобы сделать изменения более четкими, но я не знаю, как бы вы ограничили это конкретным пакетом
Клайв
Спасибо Клайв - это выглядит многообещающим крючком для расследования!
Итара

Ответы:

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()функцией, которая скоро будет удалена , поэтому я предполагаю, что она охватывает все стандартные варианты использования для загрузки узлов.

Конечно, если ваш модуль делает это, а другой модуль делает то же самое, у вас возникнет проблема, но я предполагаю, что это не обычный сценарий, и он имеет смысл только для очень конкретных случаев использования.

SiliconMind
источник
2
Извините, но нет :) Вопрос состоял в том, чтобы иметь другой класс для каждой связки . Вы меняете класс для всех связок узла типа сущности. Это не то же самое.
Бердир
@Berdir, ваше право :( ... Наличие классов для каждого пакета означает, что хранилище сущностей для узла должно быть тоже расширено, чтобы его методы загрузки могли быть переопределены для создания этих классов для каждого пакета. Что, по сути, является огромной головной болью.
SiliconMind
1
Да. drupal.org/node/2570593 - это одна из проблем, на которые я ссылался, но на которые я забыл сослаться в своем ответе.
Бердир
Я реализовал hook_entity_type_alter, чтобы установить пользовательский класс. Это тоже работает.
Еня
Когда я пытаюсь использовать этот метод, я получаю сообщение «Drupal \ Component \ Plugin \ Exception \ PluginNotFoundException: тип сущности« узел »не существует». сообщение. Я использую функцию ablecore_entity_type_build в моем файле .module. И у меня есть мой AbleNode.php в папке / src / Entity / AbleNode /
Matt
2

Я столкнулся с той же проблемой и решил создать модуль, который изменяет класс типов сущностей сущностей Drupal через систему плагинов. В настоящее время он поддерживает изменяя Node, Userи Fileклассы сущностей. При изменении Nodeправ вы можете изменять класс типов для каждого узла узла.

Проверьте описание модуля для примера:

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

Модуль использует hook_entity_type_alter () для установки класса обработчика для сущностей, которые вы предоставляете в аннотации вашего плагина.

mvdgun
источник
-1

Это старый вопрос, но реальный ответ должен быть:

Если вам нужно разное поведение в разных пакетах, то вы должны использовать разные типы сущностей, а не разные пакеты.

Объекты с пользовательским содержимым являются гражданами 1-го класса в D8. На самом деле мы оцениваем, что требуется около 30 минут, чтобы вывести новую пользовательскую сущность контента на уровень, к которому относится этот узел (что на самом деле сводится к добавлению пользовательского интерфейса формы, чтобы получить красивую боковую панель и поля псевдонима / ревизии). не включает в себя добавление страниц перевода, но это не намного больше.

Если вы еще этого не видели, взгляните на функции Generate: custom: entity консоли Drupal.

Джеймс
источник