Come posso modificare la classe del tipo di entità?


9

In Drupal 8 puoi caricare un'entità con:

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

Questo cerca le definizioni delle entità e trova quel nodo definito da Drupal \ node \ Entity \ Node - quindi (immagino) Drupal \ node \ NodeStorage creerà un'istanza di una nuova istanza Drupal \ node \ Entity \ Node .

Quello che vorrei ottenere è la sottoclasse di Drupal \ node \ Entity \ Node e la possibilità di creare un'istanza di questa sottoclasse quando è appropriato. Ad esempio, se ho un articolo sul bundle di nodi, ci sarebbe una classe:

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

E chiamerei:

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

E il ritorno sarebbe la mia Articlesottoclasse.

Posso ottenere ciò creando un nuovo tipo di entità e ricollegandolo a un'altra definizione di entità esistente, ad esempio l'esempio di nodo-articolo sarebbe questa 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);

Funziona bene (per quanto posso vedere); tuttavia, odora. Aggiunge un nuovo tipo di entità, che non è vero e potrebbe causare altri problemi in futuro.

Come definisco una sottoclasse per un pacchetto di entità in modo che il caricamento dell'entità restituisca un oggetto di quella classe?


1
Non sono sicuro che puoi fornire una classe di entità diversa per pacchetto; puoi usare hook_entity_type_alter()per rendere il cambiamento più pulito, ma non so come lo limiteresti a un pacchetto specifico
Clive

Grazie Clive - sembra un gancio promettente per indagare!
Itarato,

Risposte:


10

Crea una nuova classe nel tuo modulo che si estenda \Drupal\node\Entity\Node.

use Drupal\node\Entity\Node as BaseNode;

class MyNode extends BaseNode {
}

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

Ricorda di ricostruire la cache.

Funziona bene quando si caricano i nodi tramite il servizio di gestione del tipo di entità e l'archiviazione dei nodi. Funziona anche quando lo usi solo Drupal\node\Entity\Node::load($nid)grazie al fatto che questa load()funzione è solo un wrapper statico per la chiamata di servizio del gestore del tipo di entità fornita dalla Entityclasse che viene estesa dalla 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);
  }
}

Funziona bene anche con la funzione che sarà presto rimossa entity_load_multiple(), quindi suppongo che questo copra tutti i casi d'uso standard per il caricamento dei nodi.

Naturalmente, se il tuo modulo fa questo e un altro modulo fa lo stesso, avrai un problema, ma immagino che non sia uno scenario comune e abbia senso solo per casi d'uso molto specifici.


2
Scusa ma no :) La domanda era avere una classe diversa per pacchetto . Stai cambiando la classe per tutti i bundle del nodo del tipo di entità. Non è lo stesso.
Berdir,

@Berdir, il tuo diritto :( ... Avere classi per bundle significa che una memoria entità per nodo dovrebbe essere estesa anche in modo che i suoi metodi di caricamento possano essere sovrascritti per produrre quelle classi per bundle. Che in sostanza è un enorme mal di testa.
SiliconMind

1
Si. drupal.org/node/2570593 è uno dei problemi a cui ho fatto riferimento ma che ho dimenticato di collegare effettivamente nella mia risposta.
Berdir,

Ho implementato hook_entity_type_alter per impostare la classe personalizzata. Funziona anche
Yenya,

Quando provo questo metodo ottengo un 'Drupal \ Component \ Plugin \ Exception \ PluginNotFoundException: il tipo di entità "nodo" non esiste.' Messaggio. Sto usando la funzione ablecore_entity_type_build nel mio file .module. E ho il mio AbleNode.php nella cartella / src / Entity / AbleNode /
Matt,

2

Ho riscontrato lo stesso problema e ho deciso di creare un modulo che alterasse la classe del tipo di entità di entità Drupal tramite il sistema di plugin. Attualmente supporta alterare la Node, Usere Fileclassi di entità. Quando si modifica l' Nodeentità, è possibile modificare la classe di tipo per pacchetto di nodi.

Controlla la descrizione del modulo per un esempio:

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

Il modulo utilizza hook_entity_type_alter () per impostare una classe di gestori su entità fornite nell'annotazione del plugin.



-1

Questa è una vecchia domanda, ma la vera risposta dovrebbe essere:

Se hai bisogno di comportamenti diversi tra i pacchetti, dovresti utilizzare tipi di entità diversi, non pacchetti diversi.

Le entità di contenuto personalizzate sono cittadini di 1a classe in D8. In effetti stimiamo che ci vogliono circa 30 minuti per ottenere una nuova entità di contenuto personalizzata al livello di quel nodo (che in realtà si riduce all'aggiunta dell'interfaccia utente del modulo per ottenere il bel pannello laterale e i campi alias / revisione). non include l'aggiunta delle pagine di traduzione, ma non è molto di più.

Se non l'hai visto, dai un'occhiata alle funzioni generate: custom: entity di Drupal Console.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.