Drupal 8: Crear un bloque con un listado de nodos (parte 3)

En esta tercera y ultima parte del desarrollo del modulo, vamos a indicar cual es el nodo que se esta visualizando en caso de que estemos en la pagina final de un nodo, y tambien vamos a añadir los nodos a la cache para que no se carguen todos los nodos, cada vez que se carga el bloque.

Obtener el objeto que se esta visualizando:

Lo primero que vamos a hacer es obtener el objeto que se esta visualizando, y en caso de que sea un nodo, comprobar si alguno de los que hemos cargado, es el que estamos viendo.

Vamos al archivo drupblock.module y editamos la funcion template_preprocess_drupblock_list, para añadir el codigo necesario:

[...]

$language = \Drupal::languageManager()->getCurrentLanguage()->getId();

//Obtenemos el objeto nodo si se esta visualizando,
//El sustituto de menu_get_object en D7
$request_node = \Drupal::request()->attributes->get('node');

$request_id = '-1';
if(!is_null($request_node)) {
  if('node' == $request_node->getEntityType()->id()){
    $request_id = $request_node->id();
  }
}

$node_print = [];

foreach($nodes as $key => $node) {
  //Se obtiene el nid del nodo
  $nid = $node->id();
  //Se obtiene el alias del nodo a traves de la ruta con el Alias Manager
  $node_alias = $alias_manager->getAliasByPath('/node/' . $nid, $language);

  $node_print[$nid]['path_alias'] = $node_alias;
  $node_print[$nid]['current'] = FALSE;
  $node_print[$nid]['title'] = $node->getTitle();
  $node_print[$nid]['class'] = '';

  //Se obtiene la id del nodo del for y se marca el cargado correspondiente
  if($request_id != '-1' && $nid == $request_id){
    $node_print[$nid]['current'] = TRUE;
    $node_print[$nid]['class'] = 'current-page-item';
  }
}

$vars['nodes'] = $nodes;
$vars['nodes_print'] = $node_print;

[...]

Con esto ya tenemos en el array 'nodes_print' el nodo marcado como el actual, y la clase 'current-page-item' añadida para asi en la plantilla poder indicar cual es el nodo que se visualiza, editamos el archivo drupbloc-list.html.twig y lo dejamos como a continuacion:

{#
Variables
node_print: Array, contiene los valores para imprimir en la plantilla,
contiene los siguientes registros:
  'class' clases para imprimir en cada <li>,
  'path_alias' el alias url de la ruta del nodo
  'title' el titulo del nodo
  'current' true o false, indica si es el nodo que se esta visualizando
block_title: El titulo de la lista
nodes: Los objetos de los nodos de node print.
#}
<h3>{{ block_title }}</h3>
<ul>
{% for node in nodes_print %}
  <li class="{{ node.class }}">
    <a href="{{ node.path_alias }}">
      {% if node.current %}
        <b>{{ node.title }}</b>
      {% else %}
        {{ node.title }}
      {% endif %}
    </a>
  </li>
{% endfor %}
</ul>

Al editar la plantilla twig, añadimos un if para añadir la etiqueta <b>, si no queremos añadir ningun etiqueta y resaltar el elemento de la lista mediante css, podemos eliminar el if y dejar unicamente {{ node.title }}, como en la plantilla original que hicimos.

Pero tenemos un problema, y es la cache que guarda drupal de los bloques, con todo lo que hemos echo, cuando el bloque cargue, este se quedara con el html que haya generado, a si que para que se genere en cada carga de pagina y funcione correctamente marcado o no el nodo, debemos indicarle que no use la cache para ese bloque en concreto, a si que nos toca editar el metodo build del objeto del bloque que hemos creado, a si que nos vamos al archivo DefaultBlock.php que es donde hemos definido el bloque, y editamos el metodo build de la siguiente manera:

public function build() {
  $build = [
    '#theme' => 'node_block_list',
    '#type' => $this->configuration['content_type'],
    '#block_title' => $this->configuration['block_title'],
    '#node_number' => $this->configuration['number_nodes'],
    '#cache' => ['max-age' => 0,],
  ];

  return $build;
}

Utilizar la cache:

Este paso es opcional, pero nos puede venir muy bien como pequeña practica con la cache, lo que vamos a hacer es guardar en cache los nodos que se obtengan, y cargarla cada vez que se necesite en lugar de cargar siempre los nodos.

Comenzamos localizando nuestra funcion _drupblock_list_node_load_multiple_nodes del archivo drupblock.module y añadimos las siguientes lineas:

function _drupblock_list_node_load_multiple_nodes($type = 'blank', $number = 20){

//Se obtiene la ID del idioma que se esta usando actualmente
$langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
$cid = 'drupblock_' . $type . '_'. $langcode;

//Busca en la cache, y si hay datos guardados, los devuelve
if($cache = \Drupal::cache()->get($cid)) {
  return $cache->data;
}
[...]

//Se cargan todos los nodos a traves de sus id
$nodes = Node::loadMultiple($nids);

//Se almacenan en cache los nodos obtenidos
\Drupal::cache()->set($cid, $nodes);

return $nodes;
}

Con esto ya guardamos en cache los nodos cargados, y al entrar en la funcion comprobamos si la cache existe, y en caso de que exista, devolvemos la lista de nodos sin volver a cargarlos.

Pero ahora nos encontramos con un problema, si añadimos un nuevo nodo, y cargamos el bloque, este no aparecera, a si que debemos limpiar la cache cuando añadimos un nuevo nodo o cuando lo editamos, por si el titulo del nodo ha cambiado.

Debemos utilizar el hook_ENTITY_TYPE_presave para poder limpiar la cache cuando se crea o actualiza una entidad del tipo 'node', de modo que añadimos el siguiente codigo al archivo drupblock.mdule:

/**
 * Implements hook_ENTITY_TYPE_presave().
 */
function node_block_node_presave(Drupal\Core\Entity\EntityInterface $entity) {
  $type = $entity->getType();
  $langcode = \Drupal::languageManager()->getCurrentLanguage()->getId();
  $cid = 'drupblock_' . $type . '_'. $langcode;

  //Limpia la cache cuando se actualiza un nodo
  \Drupal::cache()->delete('drupblock_blank_'. $langcode);
  if ($cache = \Drupal::cache()->get($cid)) {
    \Drupal::cache()->delete($cid);
  }
}

Con esto ya limpiamos la cache cuando se guarde o actualice una entididad del tipo 'node'.

Con esto ya tenemos terminado el modulo, al final hemos puesto en practica la creacion de un bloque con un formulario de configuración, la creacion de una plantilla, un poco de cache y un uso basico de EntityQuery para buscar entidades.

Total de votos: 115

Entradas relacionadas

Comentarios (0)

Deja un comentario