Wie erhalte ich eine Instanz einer Entität, auf die verwiesen wird?

35

Ich habe ein Knotenobjekt mit dem Namen Bildfeld field_image. Wenn ich es tue

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

Ich erhalte ein Array mit einigen Eigenschaften anstelle eines Entitätsobjekts. Das Array sieht folgendermaßen aus:

'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

Muss ich die Dateientität manuell laden, target_idoder gibt es eine Möglichkeit, das referenzierte Entitätsobjekt automatisch von der Instanz von abzurufen Drupal\image\Plugin\Field\FieldType\ImageItem?

Warum ist die referenzierte Entität nicht über Getter erreichbar? Es könnte faul geladen werden, wenn es nicht sofort verfügbar ist.

SiliconMind
quelle
$ node-> get ('imagefield') -> first () -> getTarget (), wenn nur ein Element vorhanden ist, oder $ node-> get ('imagefield') -> referencedEntities () ... eigentlich das letzte alles was du brauchst.
@IvanJaros Nicht gerade: PHP Fatal error: Call to undefined method Drupal\image\Plugin\Field\FieldType\ImageItem::getTarget(). Funktioniert jedoch $node->get('imagefield')->referencedEntities()dank der Tatsache, dass eine $node->get('imagefield')Instanz zurückgegeben wird, EntityReferenceFieldItemListdie die referencedEntities()Methode implementiert . Ihre Lösung ist also nur teilweise - sie funktioniert für Listen, aber nicht für einzelne Felder.
SiliconMind
Ja, richtig, getTarget bezieht sich auf den Entitätsreferenzdatentyp und nicht auf das Feldelement.

Antworten:

63

Der Pfad zur referenzierten Entität ist sehr lang:

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

Natürlich kann man es immer noch über einen Linienaufruf erhalten, aber es ist immer noch umständlich und ich frage mich, warum EntityReferenceItemes keine Methode gibt, die das Referenzentitätsobjekt zurückgibt.

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

Es ist auch erwähnenswert, dass es ziemlich einfach ist, eine Reihe von Entitäten zu erhalten, auf die verwiesen wird:

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

Dies funktioniert, weil für Entitätsreferenzfelder eine $node->get($field)Instanz zurückgegeben wird, EntityReferenceFieldItemListdie eine referencedEntities()Methode implementiert .

SiliconMind
quelle
33

Sie können verwenden:

$node->field_image->entity

wenn Sie den ersten Wert wollen

Larowlan
quelle
9
Deshalb sind magische Methoden schlecht. Keine Möglichkeit, dies in Code zu dokumentieren und keine Möglichkeit, dies durch Betrachtung der implementierten Schnittstellen herauszufinden.
SiliconMind
6
Es ist vielleicht schwer, in Code zu dokumentieren, aber es gibt Dokumentation: wizzlern.nl/sites/wizzlern.nl/files/artikel/… . Aufgrund der dynamischen Struktur funktionieren Methoden nicht wirklich besser. Sie können nicht herausfinden, mit welcher Klasse Sie arbeiten, da alles dynamisch zusammengesetzt ist. Es mag schwer sein, es zum ersten Mal zu finden, aber es ist leicht genug, sich daran zu erinnern, wenn Sie es getan haben.
Berdir
1
Es gibt drupal.org/project/agcobcau, das bei der automatischen Vervollständigung in IDEs helfen wird
larowlan
11
@Berdir Ich verstehe das, aber das ist immer noch schlechtes Design. Schauen Sie sich dies an: $node->get('field_image')->entityGibt eine FileEntität zurück. Allerdings $node->get('field_image')->getEntity()gibt Eltern NodeEinheit! Ich verstehe, dass magische Methoden verwendbar sein könnten, aber sie sind PITA in größeren Projekten. Warum sich die Mühe machen, Interfaces und OO-Code zu schreiben, wenn wir trotzdem ermutigt werden, Magie zu verwenden? Sie haben geschrieben, es ist leicht genug, sich daran zu erinnern, wenn Sie es getan haben - ich bin anderer Meinung. Sobald Sie dies tun, werden Sie eine schlechte Angewohnheit entwickeln, die Ihren Code weniger lesbar und weniger wartbar macht.
SiliconMind
4
Abgestimmt. Früher habe ich das so gemacht. Dies wird jedoch manchmal unterbrochen, wenn die Entitätsreferenzen noch nicht geladen wurden (das Ergebnis ist ein Array mit target_id anstelle einer instanziierten Entität). Die von SiliconMind beschriebene Methode behandelt alle Fälle ordnungsgemäß und gibt immer eine instanziierte Entitätsklasse zurück, wenn das Feld nicht leer ist.
Alexander Varwijk
8

Was bei mir funktioniert hat war:

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

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

Die anderen Antworten ergaben nicht das erwartete Array mit den Entitätsfeldern

AlxVallejo
quelle
8

Hier erfahren Sie, wie Sie eine Entität aus einem referenzierten Feld abrufen. Ich bin mit @SiliconMind über referencedEntities einverstanden, da es ein Array von Entitätsobjekten zurückgibt, die durch Feldelement-Deltas verschlüsselt sind.

Nur einfach:

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

EntityReferenceFieldItemList :: referencedEntities

Carlos
quelle