Como altero a classe de tipo de entidade?

9

No Drupal 8, você pode carregar uma entidade com:

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

Ele procura as definições de entidade e descobre que o é definido por Drupal \ node \ Entity \ Node - então (eu acho) Drupal \ node \ NodeStorage instancia uma nova instância Drupal \ node \ Entity \ Node .

O que eu gostaria de alcançar é a subclasse de Drupal \ node \ Entity \ Node e a capacidade de instanciar essa subclasse quando for apropriado. Por exemplo, se eu tiver um artigo de pacote configurável de nó, haveria uma classe:

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

E eu ligaria para:

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

E o retorno seria minha Articlesubclasse.

Eu posso conseguir isso criando um novo tipo de entidade e conectando-o novamente a outras definições de entidade existentes, por exemplo, o exemplo de artigo do nó seria esta classe:

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

Isso funciona bem (tanto quanto eu posso ver); no entanto, cheira. Ele adiciona um novo tipo de entidade, o que não é verdade e pode causar outros problemas no futuro.

Como defino uma subclasse para um pacote de entidades para que o carregamento da entidade retorne um objeto dessa classe?

itarato
fonte
11
Não tenho certeza se você pode fornecer uma classe de entidade diferente por pacote; você pode usar hook_entity_type_alter()para fazer a mudança de forma mais limpa, mas eu não sei como você iria limitar isso a um pacote específico
Clive
Obrigado Clive - isso parece um gancho promissor para investigar!
itarato 10/09/15

Respostas:

10

Crie uma nova classe no seu módulo que se estenda \Drupal\node\Entity\Node.

use Drupal\node\Entity\Node as BaseNode;

class MyNode extends BaseNode {
}

Implementar 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');
  }
}

Lembre-se de reconstruir o cache.

Funciona bem ao carregar nós por meio do serviço do gerenciador de tipos de entidade e do armazenamento do nó. Até funciona quando você usa, Drupal\node\Entity\Node::load($nid)graças ao fato de que essa load()função é apenas um invólucro estático para a chamada de serviço do gerenciador de tipo de entidade fornecida pela Entityclasse que é estendida da Nodeclasse.

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

Isso também funciona bem com a entity_load_multiple()função que será removida em breve , então acho que isso abrange todos os casos de uso padrão para carregar nós.

Obviamente, se seu módulo fizer isso e outro módulo fizer o mesmo, você terá um problema, mas acho que não é um cenário comum, e faz sentido apenas para casos de uso muito específicos.

SiliconMind
fonte
2
Desculpe, mas não :) A questão era ter uma classe diferente por pacote . Você está alterando a classe para todos os pacotes configuráveis ​​do nó do tipo de entidade. Isso não é o mesmo.
Berdir 18/05/19
@Berdir, seu direito :( ... Ter classes por pacote significa que um armazenamento de entidade para o nó precisaria ser estendido também para que seus métodos de carregamento pudessem ser substituídos para produzir aqueles por classes de pacote. O que basicamente é uma enorme dor de cabeça.
SiliconMind
11
Sim. drupal.org/node/2570593 é um dos problemas que referi, mas esqueci de vincular na minha resposta.
Berdir 18/05/19
Eu implementei hook_entity_type_alter para definir a classe personalizada. Isso também funciona.
Yenya
Quando tento esse método, obtenho uma 'Drupal \ Component \ Plugin \ Exception \ PluginNotFoundException: o tipo de entidade "node" não existe. " mensagem. Estou usando a função ablecore_entity_type_build no meu arquivo .module. E eu tenho a minha AbleNode.php in / src / Entidade / AbleNode / pasta
Matt
2

Tive o mesmo problema e decidi criar um módulo que altera a classe de tipo de entidade das entidades Drupal por meio do sistema de plug-ins. Atualmente, ele suporta a alteração das classes Node, Usere Fileentidade. Ao alterar a Nodeentidade, você pode alterar a classe de tipo por pacote configurável do nó.

Confira a descrição do módulo para um exemplo:

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

O módulo usa hook_entity_type_alter () para definir uma classe de manipulador nas entidades que você fornece na anotação do plug-in.

mvdgun
fonte
-1

Esta é uma pergunta antiga, mas a resposta real deve ser:

Se você precisar de um comportamento diferente entre os pacotes configuráveis, deverá usar tipos de entidade diferentes, não pacotes diferentes.

Entidades de conteúdo personalizadas são cidadãos de primeira classe no D8. De fato, estimamos que leva cerca de 30 minutos para obter uma nova entidade de conteúdo personalizada no nível em que está o nó (o que realmente se resume em adicionar a UI do formulário para obter o bom painel lateral e os campos alias / revisão). não inclui adicionar as páginas de tradução, mas isso não é muito mais.

Se você ainda não viu, dê uma olhada nos recursos generate: custom: entity do Drupal Console.

James
fonte