¿Cómo modifico la clase de tipo de entidad?

9

En Drupal 8 puede cargar una entidad con:

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

Esto busca las definiciones de entidad y encuentra que ese nodo está definido por Drupal \ node \ Entity \ Node , por lo que (supongo) Drupal \ node \ NodeStorage creará una nueva instancia de Drupal \ node \ Entity \ Node .

Lo que me gustaría lograr es subclasificar Drupal \ node \ Entity \ Node y poder instanciar esta subclase cuando sea apropiado. Por ejemplo, si tengo un artículo de paquete de nodos, habría una clase:

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

Y yo llamaría:

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

Y el regreso sería mi Articlesubclase.

Puedo lograr esto creando un nuevo tipo de entidad y conectándolo de nuevo a otras definiciones de entidad existentes, por ejemplo, el ejemplo de artículo de nodo sería esta clase:

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

Esto funciona bien (tanto como puedo ver); Sin embargo, huele. Agrega un nuevo tipo de entidad, que no es cierto, y podría causar otros problemas en el futuro.

¿Cómo defino una subclase para un paquete de entidades para que cargar la entidad devuelva un objeto de esa clase?

Itarato
fuente
1
No estoy seguro de que pueda proporcionar una clase de entidad diferente por paquete; puede usar hook_entity_type_alter()para hacer el cambio de manera más limpia, pero no sé cómo limitaría eso a un paquete específico
Clive
Gracias Clive, ¡parece un gancho prometedor para investigar!
itarato

Respuestas:

10

Cree una nueva clase en su módulo que se extienda \Drupal\node\Entity\Node.

use Drupal\node\Entity\Node as BaseNode;

class MyNode extends BaseNode {
}

Poner en práctica 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');
  }
}

Recuerde reconstruir el caché.

Funciona bien al cargar nodos a través del servicio de administrador de tipo de entidad y el almacenamiento de nodos. Incluso funciona cuando solo lo usa Drupal\node\Entity\Node::load($nid)gracias al hecho de que esta load()función es solo un contenedor estático para la llamada de servicio del administrador de tipo de entidad proporcionada por la Entityclase que se extiende desde la Nodeclase.

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

Esto también funciona bien con la entity_load_multiple()función que se eliminará pronto , por lo que supongo que cubre todos los casos de uso estándar para cargar nodos.

Por supuesto, si su módulo hace esto y otro módulo hace lo mismo, tendrá un problema, pero supongo que no es un escenario común, y tiene sentido solo para casos de uso muy específicos.

SiliconMind
fuente
2
Lo siento pero no :) La pregunta era tener una clase diferente por paquete . Estás cambiando la clase para todos los paquetes del nodo de tipo de entidad. Eso no es lo mismo.
Berdir
@Berdir, su derecho :( ... ¿Tiene clases por medio de haces de que una entidad de almacenamiento para el nodo tendría que extenderse también, así que se trata de métodos de carga podrían ser anulados para producir los haces de clases por que básicamente es un enorme dolor de cabeza..
SiliconMind
1
Si. drupal.org/node/2570593 es uno de los problemas a los que me referí pero que olvidé vincular en mi respuesta.
Berdir
He implementado hook_entity_type_alter para establecer una clase personalizada. Funciona tambien
Yenya
Cuando intento este método obtengo un 'Drupal \ Component \ Plugin \ Exception \ PluginNotFoundException: el tipo de entidad "nodo" no existe ". mensaje. Estoy usando la función ablecore_entity_type_build en mi archivo .module. Y tengo mi AbleNode.php en / src / Entity / AbleNode / folder
Matt
2

Experimenté el mismo problema y decidí crear un módulo que altere la clase de tipo de entidad de las entidades de Drupal a través del sistema de complementos. Actualmente es compatible con la alteración de las clases Node, Usery Fileentidad. Al modificar la Nodeentidad, puede modificar la clase de tipo por paquete de nodos.

Consulte la descripción del módulo para ver un ejemplo:

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

El módulo usa hook_entity_type_alter () para establecer una clase de controlador en las entidades que proporcione en su anotación de complemento.

mvdgun
fuente
-1

Esta es una vieja pregunta, pero la respuesta real debería ser:

Si necesita un comportamiento diferente entre los paquetes, debería usar diferentes tipos de entidad, no paquetes diferentes.

Las entidades de contenido personalizado son ciudadanos de primera clase en D8. De hecho, estimamos que se tarda unos 30 minutos en obtener una nueva entidad de contenido personalizada al nivel de ese nodo (que realmente se reduce a agregar la interfaz de usuario del formulario para obtener el panel lateral agradable y los campos de alias / revisión). no incluye agregar las páginas de traducción, pero eso no es mucho más.

Si no lo ha visto, eche un vistazo a las características de la entidad generate: custom: de Drupal Console.

James
fuente