Как получить экземпляр ссылочной сущности?

35

У меня есть объект узла с именем поля имени field_image. Когда я делаю

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

Я получаю массив с некоторыми свойствами вместо объекта сущности. Массив выглядит так:

'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

Нужно ли вручную загружать файл с помощью объекта, target_idили есть способ автоматически получить объект объекта, на который ссылаются, из экземпляра Drupal\image\Plugin\Field\FieldType\ImageItem?

Почему ссылка на сущность не доступна через геттер? Это может быть лениво загружено, если это не доступно немедленно.

SiliconMind
источник
$ node-> get ('imagefield') -> first () -> getTarget (), если есть только один элемент, или $ node-> get ('imagefield') -> referencedEntities () ... на самом деле последний все, что тебе нужно.
@IvanJaros Не совсем: PHP Fatal error: Call to undefined method Drupal\image\Plugin\Field\FieldType\ImageItem::getTarget(). Однако $node->get('imagefield')->referencedEntities()работает благодаря тому, что $node->get('imagefield')возвращает экземпляр, EntityReferenceFieldItemListкоторый реализует referencedEntities()метод. Таким образом, ваше решение является лишь частичным - оно работает для списков, но не для отдельных полей.
SiliconMind
Да, верно, getTarget использует тип данных ссылки на сущность, а не элемент поля.

Ответы:

63

Путь к ссылочной сущности очень длинный:

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

Конечно, все еще можно получить его через один линейный вызов, но, тем не менее, это громоздко, и мне интересно, почему EntityReferenceItemне предоставляется метод, который бы возвращал объект ссылочной сущности.

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

Также стоит отметить, что довольно просто получить массив всех ссылочных объектов:

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

Это работает потому, что для ссылки на сущность поля $node->get($field)возвращает экземпляр EntityReferenceFieldItemListкоторого реализует referencedEntities()метод.

SiliconMind
источник
33

Вы можете использовать:

$node->field_image->entity

если вы хотите первое значение

larowlan
источник
9
Вот почему магические методы плохие. Нет способа документировать это в коде и нет способа выяснить это с помощью реализованных интерфейсов.
SiliconMind
6
Это трудно документировать в коде может быть, но там есть документация: wizzlern.nl/sites/wizzlern.nl/files/artikel/... . Из-за динамической структуры методы не будут работать лучше, вы не сможете точно определить, с каким классом вы работаете, поскольку все динамически создается вместе. Это может быть трудно найти в первый раз, но это достаточно легко запомнить, как только вы это сделали.
Бердир
1
Существует drupal.org/project/agcobcau, который поможет с автозаполнением в IDE
larowlan
11
@Berdir Я понимаю, что это все-таки плохой дизайн. Посмотрите на это: $node->get('field_image')->entityвозвращает Fileсущность. Однако $node->get('field_image')->getEntity()возвращает родительскую Nodeсущность! Я понимаю, что магические методы могут быть полезны, но они являются PITA в более крупных проектах. Зачем беспокоиться о написании интерфейсов и оо-кода, если мы все равно рекомендуем использовать магию? Вы написали, что достаточно легко запомнить, как только вы это сделали - я не согласен. Как только вы начнете это делать, вы разовьете действительно плохую привычку, которая сделает ваш код менее читаемым и менее обслуживаемым.
SiliconMind
4
Downvoted. Раньше я делал это так. Однако это иногда будет нарушаться, если ссылки на сущности не были загружены ранее (результатом будет массив с target_id вместо экземпляра сущности). Метод, описанный SiliconMind, будет правильно обрабатывать все случаи и всегда будет возвращать экземпляр класса сущности, если поле не пустое.
Александр Варвийк
8

Что сработало для меня:

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

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

Другие ответы не дали массива полей сущностей, который я ожидал

AlxVallejo
источник
8

Как получить сущность из поля, на которое есть ссылка. Я согласен с @SiliconMind в отношении referencedEntities, он возвращает массив объектов-сущностей с ключевыми точками поля.

Просто:

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

EntityReferenceFieldItemList :: referencedEntities

Carlos
источник