Sichere und elegante Möglichkeit, über Felder auf verschachtelte Entitäten zuzugreifen

7

Ich habe verschiedene Ansätze für den Zugriff auf Entitätswerte in der Themenebene gesehen. Der folgende Code ist nur ein einfaches Beispiel mit magischen Methoden. Es wird davon ausgegangen, dass alle Werte festgelegt sind. Wenn ein Teil davon einen NULL-Wert zurückgibt, treten meiner Erfahrung nach Fehler auf.

$value = $node->field_paragraph
    ->entity->field_media
    ->entity->field_file
    ->entity->field_text->value;

Es gibt Methoden wie ->hasFieldund ->count()um Dinge zu überprüfen, und ich habe eine Vielfalt in meinen Themen. Ich kann den Job erledigen, aber manchmal fühlt es sich hässlich an. Ich interessiere mich für die Codierungsmuster, mit denen Entwickler Entitätsreferenzen sicher und elegant durchforsten.

simesy
quelle
1
Es gibt ein Contrib-Modul namens reference_map. Es ist nicht sehr benutzerfreundlich, aber es wurde ausdrücklich für dieses Problem geschrieben.
Charles Bamford

Antworten:

7

Vorschlag: Erstellen Sie ein Domänenobjekt mit der Logik.

Normalerweise stellen diese Entitäten etwas dar, das zu Ihrer Geschäftsdomäne passt.

In Ihrer Instanz kann der Knoten beispielsweise ein Ereignis sein.

Sie können also ein Domänenobjekt namens modellieren EventWrapper.

<?php

namespace Drupal\my_domain;
use Drupal\node\NodeInterface;
use Drupal\media\MediaInterface;
use Drupal\file\FileInterface;

class EventWrapper {
  protected $node;
  public static function fromNode(NodeInterface $node): EventWrapper {
    $instance = new static();
    $instance->node = $node;
    return $instance;
  }
  public function getMedia() : ?MediaInterface {
    if ($this->node->hasField('field_media') && !$this->node->get('field_media')->isEmpty()) {
      return $this->node->field_media->entity;
    }
    return NULL;
  }
  public function getMediaImage() : ?FileInterface {
    if (($media = this->getMedia()) && $media->hasField('field_file') && !$media->get('field_file')->isEmpty()) {
      return $media->field_file->entity;
    }
    return NULL;
  }
  public function getImageCaption(): ?string {
    if (($file = this->getMediaImage()) && $file->hasField('field_text') && !$file->get('field_text')->isEmpty()) {
      return $file->field_text->value;
    }
    return NULL;
  }
}

Dann in Ihrem Code:

<?php

$image_caption = EventWrapper::fromNode($node)->getImageCaption();
Larowlan
quelle
6

Obwohl Sie Absätze normalerweise rekursiv rendern, können Sie eine feste Struktur nicht rekursiv abrufen, indem Sie sie mit foreach-Schleifen neu erstellen:

foreach ($node->field_paragraph->referencedEntities() as $paragraph) {
  foreach ($paragraph->field_media->referencedEntities() as $media) {
    ...
  }
}

Dies vermeidet den Zugriff auf leere Felder und kann mehrwertige Felder verarbeiten.

4k4
quelle
1

Um die großartige Antwort um 4k4 zu erweitern, die ein Muster zeigt, das wir häufig verwenden, aber die Existenz des Feldes nicht abdeckt, können Sie eine einfache Klasse erstellen, die nach Larowlans großartiger Antwort strukturiert ist :

class EntityReferenceItemListHelper {
   protected $fieldItemList;
   static function create(?EntityReferenceFieldItemListInterface $fieldItemList) {
     $instance = new static;
     $instance->fieldItemList = $fieldItemList;
   }
   public function referencedEntities(): array {
     return $this->fieldItemList ? $this->fieldItemList->referencedEntities() : [];
   }
}

und dann foreach (EntityReferenceItemListHelper::create($paragraph->field_media)->referencedEntities() as $media) {

Smartsheet eng
quelle