Como processar programaticamente o campo de um nó respeitando as configurações do modo de exibição?

9

Eu quero renderizar o campo de um nó dentro de um bloco. Funciona assim:

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

Mas isso não é 100% como se eu apenas renderizasse o campo normalmente, tornando-o visível nas configurações do modo de exibição.

Alex
fonte

Respostas:

0

Eu acho que o modo de exibição deve ser aplicado ao nó, não ao campo. Portanto, você precisa obter o viewbuilder e renderizar o nó. Depois, você pode selecionar a matriz renderizada para o campo na matriz de renderização node'r. Mais ou menos assim:

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

PS Você precisa "[EntityTypeManager]" de qualquer forma injetado como serviço @ entity_type.manager. Ou obtenha-o em seu Block-Plugin create () em $ container-> get ('entity_type.manager').

Rainer Feike
fonte
11
não exatamente. $nodeviewtem #nodecomo chave
Alex
11
Também, isto torna o nó, os campos não separados
Alex
11
Sim, eu processo o nó (e todos os seus campos). Mas é isso que você ajusta nas configurações do modo de exibição. Talvez eu tenha entendido sua pergunta errado.
Rainer Feike
11
"$ nodeview [youfield-here];" é nulo, pelo menos no Drupal 8.6.x
Onkeltem 16/04
11
Substitua "yourfield-here" pelo nome da máquina do seu campo.
Rainer Feike
28

Para renderizar um único campo com a configuração de exibição de um modo de exibição, você pode usar o view()método do campo:

Exemplo para renderizar a imagem no formato teaser:

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

Ou o corpo completamente:

$build['body'] = $node->body->view('full');
4k4
fonte
11
Infelizmente, este não respeita as configurações do modo de vista, como rótulos e formatador configurações
Alex
11
Isso deve funcionar, você pode até usar o twig debug com este comando. Se você fornecer um modo de exibição existente como string, o campo será formatado com isso. Se você fornecer uma matriz, poderá ['label' => 'inline' ]
definir
11
Eu acredito que já tentei isso, mas não funcionou. vou tentar de novo. graças até agora
Alex
11
Acho que está respeitando o formatador, mas não as configurações do formatador. A saída disso inclui as configurações corretas.
Grayside
11
Isto essencialmente começou-me a resposta, onde posso obter minha variável em .twig: $vars['var_name'] = $node_object->field_name->view()[0]; e depois em galho, I pode render {{var_name}}
bdanin
4

Esta resposta baseia-se em 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 renderizar completamente programaticamente o campo que você termina chamando renderRoot(), que estabelece um contexto de renderização separado do que as respostas típicas da página usariam - um único contexto de renderização para uma solicitação ou sub-solicitação. Também poderíamos usar renderPlain(), mas isso escaparia de todas as coisas.

Na substituição do Drush, mas não na execução normal da página, isso lançou um aviso para mim:

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

relacionado à resposta de Alex , aqui está como eu a modifiquei para usar o config_pages e criar um bloco 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;

}

Provavelmente é melhor renderizar campos arbitrários a partir de uma configuração config_pages em vez de extrair dados de um nó, mas acho que depende realmente do caso de uso específico sobre qual método é o melhor.

bdanin
fonte
2

Graças à resposta de Rainer Feike, cheguei à solução:

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

}

Usando $viewBuilder->viewFieldeu posso processar todos os campos separadamente que eu preciso. Eu só preciso descobrir como adicionar o cache, dependendo das configurações do modo de exibição, mas essa é outra questão :)

Alex
fonte