Comment obtenir une instance d'entité référencée?

35

J'ai un objet nœud avec un champ d'image nommé field_image. Quand je fais

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

Je reçois un tableau avec des propriétés au lieu d'objet entité. Le tableau ressemble à ceci:

'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

Dois-je toujours charger l'entité de fichier en utilisant target_idou existe-t-il un moyen d'obtenir automatiquement un objet d'entité référencé à partir d'une instance de Drupal\image\Plugin\Field\FieldType\ImageItem?

Pourquoi l'entité référencée n'est pas accessible via getter? Il pourrait être chargé paresseux s'il n'est pas disponible immédiatement.

SiliconMind
la source
$ node-> get ('imagefield') -> first () -> getTarget () s'il n'y a qu'un seul élément ou $ node-> get ('imagefield') -> référencéEntities () ... en fait, le dernier est tout ce dont tu as besoin.
@IvanJaros Pas exactement: PHP Fatal error: Call to undefined method Drupal\image\Plugin\Field\FieldType\ImageItem::getTarget(). Cependant $node->get('imagefield')->referencedEntities()fonctionne grâce au fait $node->get('imagefield')retourne instance de EntityReferenceFieldItemListqui implémente la referencedEntities()méthode. Votre solution n’est donc que partielle: elle fonctionne pour les listes mais pas pour les champs uniques.
SiliconMind
Oui, le getTarget est sur un type de données de référence d'entité, pas d'élément de champ.

Réponses:

63

Le chemin d'accès à l'entité référencée est très long:

// $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.

Bien sûr, on peut toujours l'obtenir via un seul appel au titre, mais cela reste quand même encombrant et je me demande pourquoi on EntityReferenceItemne fournit pas de méthode permettant de renvoyer l'objet d'entité de référence.

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

Il est également intéressant de noter qu'il est assez facile d'obtenir un tableau de toutes les entités référencées:

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

Cela fonctionne car pour les champs de référence d'entité, une $node->get($field)instance de EntityReferenceFieldItemListlaquelle implémente la referencedEntities()méthode est renvoyée.

SiliconMind
la source
33

Vous pouvez utiliser:

$node->field_image->entity

si vous voulez la première valeur

Larowlan
la source
9
C'est pourquoi les méthodes magiques sont mauvaises. Pas moyen de documenter cela dans le code ni de comprendre cela en regardant les interfaces implémentées.
SiliconMind
6
Il est difficile de documenter en code peut-être, mais il existe une documentation: wizzlern.nl/sites/wizzlern.nl/files/artikel/… . En raison de la structure dynamique, les méthodes ne fonctionneraient pas vraiment mieux, vous ne pouvez pas savoir avec quelle classe vous travaillez exactement, car tout est construit ensemble de manière dynamique. C'est peut-être difficile à trouver pour la première fois, mais il est assez facile de s'en souvenir une fois que vous l'avez fait.
Berdir
1
Il y a drupal.org/project/agcobcau qui aidera à l'achèvement automatique dans les IDE
larowlan
11
@Berdir Je comprends que, cependant, c'est toujours une mauvaise conception. Regardez ceci: $node->get('field_image')->entityrenvoie l' Fileentité. Cependant $node->get('field_image')->getEntity()retourne mère Nodeentité! Je comprends que les méthodes magiques puissent être utilisables, mais ce sont des PITA dans des projets plus importants. Pourquoi s'embêter à écrire des interfaces et du code oo si on nous encourage de toute façon à utiliser la magie? Vous avez écrit qu'il est assez facile de vous rappeler une fois que vous l'avez fait - je ne suis pas d'accord. Une fois que vous aurez commencé à le faire, vous développerez une très mauvaise habitude qui rendra votre code moins lisible et moins gérable.
SiliconMind
4
Moins voté. Je le faisais de cette façon. Cependant, cela peut parfois casser si les références d'entité n'ont pas été chargées auparavant (le résultat sera un tableau avec target_id au lieu d'une entité instanciée). La méthode décrite par SiliconMind gérera correctement tous les cas et retournera toujours une classe d'entités instanciée si le champ n'est pas vide.
Alexander Varwijk
8

Ce qui a fonctionné pour moi a été:

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

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

Les autres réponses ne produisaient pas le tableau de champs d'entité que j'attendais

AlxVallejo
la source
8

Pour obtenir une entité à partir d'un champ référencé. Je suis d’accord avec @SiliconMind à propos de referenceEntities, il renvoie un tableau d’objets d’entité associé à des deltas d’éléments de champ.

Juste simple:

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

EntityReferenceFieldItemList :: référencéesEntities

Carlos
la source