¿Cómo puedo representar programáticamente el campo de un nodo respetando la configuración del modo de vista?

9

Quiero representar el campo de un nodo dentro de un bloque. Funciona así:

<?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;

Pero esto no es 100% como si simplemente renderizara el campo normalmente, haciéndolo visible en la configuración del modo de vista.

Alex
fuente

Respuestas:

0

Creo que el modo de vista debería aplicarse al nodo, no al campo. Por lo tanto, debe obtener el generador de vistas y representar el nodo. Luego puede elegir la matriz renderizada para el campo de la matriz de renderización del nodo. Algo así:

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

PD: De todos modos, debe "[EntityTypeManager]" inyectado como servicio @ entity_type.manager. O consígalo en su Block-Plugin create () de $ container-> get ('entity_type.manager').

Rainer Feike
fuente
1
no exactamente. $nodeviewtiene #nodecomo clave
Alex
1
Además, esto representa el nodo, no campos separados
Alex
1
Sí, renderizo el nodo (y todos sus campos). Pero esto es lo que ajusta en la configuración del modo de vista. Tal vez me equivoqué de pregunta.
Rainer Feike
1
"$ nodeview [youfield-here];" es nulo, al menos en Drupal 8.6.x
Onkeltem
1
Reemplace "yourfield-here" con el nombre de la máquina de su campo.
Rainer Feike
28

Para representar un solo campo con la configuración de visualización de un modo de vista, puede usar el view()método del campo:

Ejemplo para representar la imagen en formato teaser:

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

O el cuerpo completo:

$build['body'] = $node->body->view('full');
4k4
fuente
1
desafortunadamente, esto no respeta la configuración del modo de vista, como las etiquetas y la configuración del formateador
Alex
1
Esto debería funcionar, incluso puede usar la depuración de ramitas con este comando. Si proporciona un modo de vista existente como cadena, el campo se formateará con esto. Si proporciona una matriz, puede dar su propia configuración de pantalla, por ejemplo['label' => 'inline' ]
4k4
1
Creo que ya lo intenté pero no funcionó. lo intentaré otra vez. gracias hasta ahora
Alex
1
Creo que respeta el formateador, pero no la configuración del formateador. El resultado de esto incluye la configuración correcta.
Grayside
1
esto esencialmente me llevó a la respuesta, donde puedo obtener mi variable en .twig: $vars['var_name'] = $node_object->field_name->view()[0]; y luego en twig, puedo renderizar {{var_name}}
bdanin
4

Esta respuesta se basa en 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);

Para procesar completamente el campo que finaliza llamando renderRoot(), lo que establece un contexto de procesamiento separado del que usarían las respuestas de página típicas: un contexto de procesamiento único para una solicitud o sub-solicitud. También podríamos usar renderPlain(), pero luego se nos escaparía todo

En la respuesta Drush pero no en la ejecución normal de la página, esto me lanzó una advertencia:

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
fuente
2

relacionado con la respuesta de Alex , así es como lo modifiqué para usar config_pages y construir un bloque 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;

}

Probablemente sea mejor representar campos arbitrarios desde una configuración config_pages en lugar de extraer datos de un nodo, pero supongo que realmente depende del caso de uso específico en cuanto a qué método es el mejor.

bdanin
fuente
2

Gracias a la respuesta de Rainer Feike, llegué a la solución:

<?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;

}

Utilizando $viewBuilder->viewFieldpuedo representar cualquier campo por separado que necesito. Solo necesito saber cómo agregar el almacenamiento en caché dependiendo de la configuración del modo de vista, pero esta es otra pregunta :)

Alex
fuente