32

I have a node object with image field named field_image. When I do

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

I get array with some properties instead of entity object. The array looks like this:

'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

Do I have to manullay load the file entity using target_id or there is a way to automatically get referenced entity object from instance of Drupal\image\Plugin\Field\FieldType\ImageItem?

Why the referenced entity is not accessible via getter? It could be lazy loaded if it's not available immediately.

  • $node->get('imagefield')->first()->getTarget() if there is only one item or $node->get('imagefield')->referencedEntities() ... actually that last one is all you need. – user21641 Jan 10 '16 at 14:52
  • @IvanJaros Not exactly: PHP Fatal error: Call to undefined method Drupal\image\Plugin\Field\FieldType\ImageItem::getTarget(). However $node->get('imagefield')->referencedEntities() works thanks to the fact $node->get('imagefield') returns instance of EntityReferenceFieldItemList which implements referencedEntities() method. So your solution is only partial - it works for lists but not for single fields. – SiliconMind Jan 10 '16 at 15:18
  • Yeah right, the getTarget is on entity reference data type, not field item. – user21641 Jan 10 '16 at 15:23
61

The path to referenced entity is very 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.

Of course one can still get it via one liner call, but still, it is cumbersome and I wonder why EntityReferenceItem does not provide method that would return the reference entity object.

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

It's also worth noting that it's quite easy to get array of all referenced entities:

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

It works because for entity reference fields $node->get($field) returns instance of EntityReferenceFieldItemList which implements referencedEntities() method.

32

You can use:

$node->field_image->entity

if you want the first value

  • 8
    This is why magic methods are bad. No way to document this in code and no way to figure out this by looking at implemented interfaces. – SiliconMind Jan 10 '16 at 20:33
  • 5
    It's hard to document in code maybe, but there is documentation: wizzlern.nl/sites/wizzlern.nl/files/artikel/…. Due to the dynamic structure, methods wouldn't really work better, you can't figure out which class you're working with exactly as everything is built together dynamically. It might be hard to find for the first time, but it's easy enough to remember once you did. – Berdir Jan 10 '16 at 21:17
  • 1
    There is drupal.org/project/agcobcau which will help with auto completion in IDEs – larowlan Jan 10 '16 at 23:03
  • 9
    @Berdir I do understand that, however this is still bad design. Look at this: $node->get('field_image')->entity returns File entity. However $node->get('field_image')->getEntity() returns parent Node entity! I do understand that magic methods might be usable, but they are PITA in larger projects. Why bother writing interfaces and oo code if we are encouraged to use magic anyway? You wrote it's easy enough to remember once you did - I disagree. Once you start doing this, you'll develop really bad habit that will make your code less readable and less maintainable. – SiliconMind Jan 11 '16 at 8:44
  • 4
    Downvoted. I used to do it this way. However this will sometimes break if the entity references haven't been loaded before (the result will be an array with target_id instead of an instantiated entity). The method outlined by SiliconMind will properly handle all cases and will always return an instantiated entity class if the field is not empty. – Alexander Varwijk Nov 20 '17 at 15:09
7

What worked for me was:

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

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

The other answers didn't produce the entity fields array I was expecting

5

For how to get an entity from a referenced field. Im agree with @SiliconMind about referencedEntities it return an array of entity objects keyed by field item deltas.

Just simple:

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

EntityReferenceFieldItemList::referencedEntities

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.