Como obter instância da entidade referenciada?

35

Eu tenho um objeto de nó com o campo de imagem nomeado field_image. Quando eu faço

$node
  ->get('field_image')
  ->first()
  ->getValue()

Recebo matriz com algumas propriedades em vez de objeto de entidade. A matriz fica assim:

'target_id' => string '8' (length=1)
'alt' => string '' (length=0)
'title' => string '' (length=0)
'width' => string '587' (length=3)
'height' => string '458' (length=3)
'_loaded' => boolean true
  '_accessCacheability' => 
    object(Drupal\Core\Cache\CacheableMetadata)[1092]
      protected 'cacheContexts' => 
        array (size=0)
          ...
      protected 'cacheTags' => 
        array (size=0)
          ...
      protected 'cacheMaxAge' => int -1

Preciso carregar manualmente a entidade do arquivo usando target_idou existe uma maneira de obter automaticamente o objeto de entidade referenciado da instância de Drupal\image\Plugin\Field\FieldType\ImageItem?

Por que a entidade referenciada não está acessível via getter? Pode ser carregado preguiçosamente se não estiver disponível imediatamente.

SiliconMind
fonte
$ node-> get ('imagefield') -> first () -> getTarget () se houver apenas um item ou $ node-> get ('imagefield') -> referencedEntities () ... na verdade esse último é tudo que você precisa.
@IvanJaros não exatamente: PHP Fatal error: Call to undefined method Drupal\image\Plugin\Field\FieldType\ImageItem::getTarget(). No entanto, $node->get('imagefield')->referencedEntities()funciona graças ao fato de $node->get('imagefield')retornar a instância da EntityReferenceFieldItemListqual implementa o referencedEntities()método. Portanto, sua solução é apenas parcial - funciona para listas, mas não para campos únicos.
SiliconMind
Sim, o getTarget está no tipo de dados de referência da entidade, não no item de campo.

Respostas:

63

O caminho para a entidade referenciada é muito longo:

// $id = some node ID
// $field = field name for entity reference field
$node = Node::load($id);

/** @var \Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem $referenceItem */
$referenceItem = $node->get($field)->first();

/** @var \Drupal\Core\Entity\Plugin\DataType\EntityReference $entityReference */
$entityReference = $referenceItem->get('entity');

/** @var \Drupal\Core\Entity\Plugin\DataType\EntityAdapter $entityAdapter */
$entityAdapter = $entityReference->getTarget();

/** @var \Drupal\Core\Entity\EntityInterface $referencedEntity */
$referencedEntity = $entityAdapter->getValue();

// At this point $referencedEntity is the referenced entity object.

É claro que ainda é possível obtê-lo através de uma chamada de linha, mas ainda assim é complicado e eu me pergunto por EntityReferenceItemque não fornece um método que retorne o objeto da entidade de referência.

$referencedEntity = $node
  ->get($field)
  ->first()
  ->get('entity')
  ->getTarget()
  ->getValue()
;

Também é importante notar que é muito fácil obter uma matriz de todas as entidades referenciadas:

$node->get($field)->referencedEntities();

Funciona porque para os campos de referência da entidade $node->get($field)retorna a instância da EntityReferenceFieldItemListqual implementa o referencedEntities()método.

SiliconMind
fonte
33

Você pode usar:

$node->field_image->entity

se você quer o primeiro valor

larowlan
fonte
9
É por isso que os métodos mágicos são ruins. Não há como documentar isso no código e como descobrir isso observando as interfaces implementadas.
SiliconMind
6
É difícil documentar em código talvez, mas não é a documentação: wizzlern.nl/sites/wizzlern.nl/files/artikel/... . Devido à estrutura dinâmica, os métodos não funcionariam realmente melhor, você não pode descobrir com qual classe está trabalhando exatamente porque tudo é construído dinamicamente. Pode ser difícil encontrá-lo pela primeira vez, mas é fácil lembrar quando você o fez.
Berdir
11
drupal.org/project/agcobcau que vai ajudar com preenchimento automático em IDEs
larowlan
11
@ Berdir Eu entendo que, no entanto, isso ainda é um design ruim. Veja isto: $node->get('field_image')->entityretorna Fileentidade. No entanto, $node->get('field_image')->getEntity()retorna Nodeentidade pai ! Entendo que os métodos mágicos podem ser úteis, mas são PITA em projetos maiores. Por que se preocupar em escrever interfaces e oo código se somos incentivados a usar magia de qualquer maneira? Você escreveu que é fácil lembrar uma vez que você fez - eu discordo. Quando você começar a fazer isso, desenvolverá um péssimo hábito que tornará seu código menos legível e menos sustentável.
SiliconMind
4
Votado. Eu costumava fazer assim. No entanto, isso às vezes será interrompido se as referências da entidade não tiverem sido carregadas antes (o resultado será uma matriz com target_id em vez de uma entidade instanciada). O método descrito por SiliconMind manipulará adequadamente todos os casos e sempre retornará uma classe de entidade instanciada se o campo não estiver vazio.
Alexander Varwijk
8

O que funcionou para mim foi:

$entity_id = $node->get('field_contact')->first()->getValue()['target_id'];

$entity = Node::load($entity_id)->toArray();

As outras respostas não produziram a matriz de campos de entidade que eu esperava

AlxVallejo
fonte
8

Para saber como obter uma entidade de um campo referenciado. Estou de acordo com @SiliconMind sobre referencedEntities. Ele retorna uma matriz de objetos de entidade codificada por deltas de itens de campo.

Simples:

$node->get('field_name')->referencedEntities();

EntityReferenceFieldItemList :: referencedEntities

Carlos
fonte