Jak mogę programowo renderować pole węzła z uwzględnieniem ustawień trybu widoku?

9

Chcę wyrenderować pole węzła w bloku. Działa to tak:

<?php

if ($node) {
  if (isset($node->field_body_secondary) && $field = $node->field_body_secondary->value) {
    $markup = render($field);
    $build = array(
      '#type' => 'markup',
      '#markup' => $markup,
    );
  }
}

return $build;

Ale to nie jest 100%, jakbym po prostu renderował pole normalnie, dzięki czemu byłoby widoczne w ustawieniach trybu widoku.

Alex
źródło

Odpowiedzi:

0

Myślę, że tryb widoku powinien być zastosowany do węzła, a nie do pola. Musisz więc pobrać program do tworzenia widoków i wyrenderować węzeł. Następnie możesz wybrać renderowaną tablicę dla pola z tablicy renderującej węzła. Coś w stylu:

$vb = [EntityTypeManager]->getViewBuilder('node'); // Drupal\node\NodeViewBuilder
$nodeview = $vb->view($node, $viewmode);
$fieldrenderarray = $nodeview[youfield-here];

PS Musisz „[EntityTypeManager]” w każdym razie wstrzyknąć jako usługę @ entity_type.manager. Lub pobierz go w Block-Plugin create () z $ container-> get ('entity_type.manager').

Rainer Feike
źródło
1
nie do końca. $nodeviewma #nodejako klucz
Alex
1
ponadto renderuje węzeł, a nie oddzielne pola
Alex
1
Tak, renderuję węzeł (i wszystkie jego pola). Ale to właśnie dostosowujesz w ustawieniach trybu widoku. Może źle zrozumiałem twoje pytanie.
Rainer Feike
1
„$ nodeview [youfield-here];” jest zerowy, przynajmniej na Drupal 8.6.x
Onkeltem 16.04.19
1
Zamień „twoje pole-tutaj” na nazwę komputera swojego pola.
Rainer Feike
29

Aby wyrenderować pojedyncze pole z ustawieniem wyświetlania trybu widoku, możesz użyć view()metody pola:

Przykład renderowania obrazu w formacie zwiastuna:

$build['image'] = $node->field_image->view('teaser');

Lub ciało w całości:

$build['body'] = $node->body->view('full');
4k4
źródło
1
niestety nie przestrzega to ustawień trybu widoku, takich jak ustawienia etykiet i formatyzatora
Alex
1
To powinno działać, możesz nawet użyć debugowania gałązek za pomocą tego polecenia. Jeśli podasz istniejący tryb widoku jako ciąg, pole zostanie sformatowane tym. Jeśli podasz tablicę, możesz podać własne ustawienia wyświetlania, na przykład['label' => 'inline' ]
4k4
1
Myślę, że już tego próbowałem, ale to nie zadziałało. spróbuje znowu. dzięki dotychczas
Alex
1
Uważam, że szanuje formatyzator, ale nie jego ustawienia. Dane wyjściowe obejmują prawidłowe ustawienia.
Grayside
2
to zasadniczo doprowadziło mnie do odpowiedzi, gdzie mogę uzyskać moją zmienną w .twig: $vars['var_name'] = $node_object->field_name->view()[0]; a następnie w gałązce, mogę renderować {{var_name}}
bdanin
4

Ta odpowiedź opiera się na https://drupal.stackexchange.com/a/208061/394

// Designate the field we want to render.
$field_name = 'body';
// Retrieve a render array for that field with the given view mode.
$render_array = $entity->$field_name->view('full');
// Render the result.
\Drupal::service('renderer')->renderRoot($render_array);

Aby całkowicie programowo renderować pole, które kończysz przez wywołanie renderRoot(), co ustanawia odrębny kontekst renderowania od typowych odpowiedzi strony - pojedynczy kontekst renderowania dla żądania lub żądania częściowego. Moglibyśmy również użyć renderPlain(), ale wtedy uciekłoby od wszystkich rzeczy.

W replice Drusha, ale nie w normalnym wykonaniu strony, wygenerowało to ostrzeżenie:

PHP warning:  DOMDocument::loadHTML(): Tag drupal-entity invalid in Entity, line: 1 in /drupal/core/lib/Drupal/Component/Utility/Html.php on line 286
Grayside
źródło
2

związane z odpowiedzią Alexa , oto jak zmodyfikowałem ją, aby używał config_pages i budowałem blok global_footer:

<?php

public function build() {
$config_name = 'global_footer';
$config = config_pages_config($config_name);
$build = array();
$markup = array();

$fieldsToRender = array(
  'field_body', 'field_foo', 'field_bar'
);

$viewmode = 'default';
$entityType = 'config_pages';
$display = entity_get_display($entityType, $config_name, $viewmode);
$viewBuilder = \Drupal::entityTypeManager()->getViewBuilder($entityType);

foreach ($fieldsToRender as $field_name) {
  if (isset($config->{$field_name}) && $field = $config->{$field_name}) {
    $fieldRenderable = $viewBuilder->viewField($field, $display->getComponent($field_name));
    if (count($fieldRenderable) &&! empty($fieldRenderable)) {
      $markup[] = \Drupal::service('renderer')->renderRoot($fieldRenderable);
    }
  }
}

if (count($markup)) {
  $build = array(
    '#type' => 'markup',
    '#markup' => implode("", $markup),
  );
}

return $build;

}

Prawdopodobnie lepiej jest renderować dowolne pola z konfiguracji config_pages w przeciwieństwie do pobierania danych z węzła, ale myślę, że tak naprawdę zależy to od konkretnego przypadku użycia, który sposób jest najlepszy.

bdanin
źródło
2

Dzięki odpowiedzi Rainer Feike doszedłem do rozwiązania:

<?php

public function build() {
  $node = \Drupal::routeMatch()->getParameter('node');
  $build = array();
  $markup = array();

  $fieldsToRender = array(
    'field_node_ref', 'field_foo', 'field_bar',
  );

  $viewmode = 'default';
  $entityType = 'node';
  $display = entity_get_display($entityType, $node->getType(), $viewmode);
  $viewBuilder = \Drupal::entityTypeManager()->getViewBuilder($entityType);

  foreach ($fieldsToRender as $field_name) {
    if (isset($node->{$field_name}) && $field = $node->{$field_name}) {
      $fieldRenderable = $viewBuilder->viewField($field, $display->getComponent($field_name));
      if (count($fieldRenderable) &&! empty($fieldRenderable)) {
        $markup[] = \Drupal::service('renderer')->renderRoot($fieldRenderable);
      }
    }  
  }

  if (count($markup)) {
    $build = array(
      '#type' => 'markup',
      '#markup' => implode("", $markup),
    );
  }

  return $build;

}

Za pomocą $viewBuilder->viewFieldmogę renderować dowolne pola osobno, których potrzebuję. Muszę tylko dowiedzieć się, jak dodać buforowanie w zależności od ustawień trybu widoku, ale to kolejne pytanie :)

Alex
źródło