D8 Theming Modules - pierregermain/MyDrupal GitHub Wiki

Arrays Renderizables

  • Servicio: renderer
  • Clase Renderer
  • Se encarga de convertir el array en html

Ejemplos cuando se llama a Renderer

  • Cuando un controlador devuelve una página.
  • Cuando un bloque devuelve su $build en su método build().
  • Cuando se devuelve $form al crear un formulario.

Ejemplo 1: Tabla

//Example 2: table
$header = ['Column 1', 'Column 2', 'Column 3'];
$rows[] = ['A', 'B', 'C'];
$rows[] = ['D', 'E', 'F'];
$build['mymodule_theming_table'] = [
  '#type' => 'table',
  '#header' => $header,
  '#rows' => $rows,
];

Ejemplo 2: Renderizar usando una plantilla (item-list.html.twig)

$list = ['Item 1', 'Item 2', 'Item 3'];
$build['mymodule_theming_list'] = [
  '#theme' => 'item_list',
  '#title' => $this->t('List of items'),
  '#list_type' => 'ol',
  '#items' => $list,
];

Propiedades de los arrays renderizables

  • los arrays renderizables se componen de dos tipos de elementos:

    • propiedades (properties): Empiezan con '#'. Describen cómo renderizar el array
    • hijos (children): Son arrays renderizables.
  • Los elementos de formulario son un subconjunto de los elementos renderizables.

Propiedades más usadas:

#type

#theme

Plantilla a ser usada para renderizar

#markup

#plain_text

#allowed_tags

para limitar las etiquetas HTML posibles en una cadena añadida a través de #markup

#prefix/#suffix

#pre_render

Funciones a ser ejecutadas antes de renderizar.

#post_render

Funciones que actúan sobre el html generado

#theme_wrappers

Servicio Renderer

Una vez inyectado podemos usar: $this->renderer->render($build);

Elementos Hijos

  public function renderChildren() {
    $list = ['Item 1', 'Item 2', 'Item 3'];
    $build = [
      'container' => [
        '#prefix' => '<div id="container">',
        '#suffix' => '</div>',
        '#markup' => $this->t('This is a container div'),
        'list' => [
          '#theme' => 'item_list',
          '#title' => $this->t('List of items'),
          '#list_type' => 'ol',
          '#items' => $list,
        ],
      ],
    ];
    return $build;

Esto nos devuelve

<div id="container">This is a container div
    <div class="item-list">
        <h3>Lista de ítems</h3>
        <ol>
            <li>Item 1</li>
            <li>Item 2</li>
            <li>Item 3</li>
        </ol>
    </div>
</div>

Elementos renderizables

dropbutton

    $build['dropbutton'] = [
      '#type' => 'dropbutton',
      '#links' => [
        'view' => [
          'title' => $this->t('View'),
          'url' => Url::fromRoute('entity.node.canonical', ['node' => $nid], []),
        ],
        'edit' => [
          'title' => $this->t('Edit'),
          'url' => Url::fromRoute('entity.node.edit_form', ['node' => $nid], []),
        ],
        'delete' => [
          'title' => $this->t('Delete'),
          'url' => Url::fromRoute('entity.node.delete_form', ['node' => $nid], []),
        ],
      ],
    ];

operations

https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!Element!Operations.php/class/Operations/8

more_link

$build['more_link'] = [
'#type' => 'more_link',
'#url' => Url::fromRoute('mymodule_theming.list')
];

toolbar_item

  • Se usa dentro del hook_toolbar

Ejemplo: Módulo masquerade

/**
* Implements hook_toolbar().
*
*/
function masquerade_toolbar() {
$items = array();
if (\Drupal::service('masquerade')->isMasquerading()) {
$items['masquerade_switch_back'] = array(
'#type' => 'toolbar_item',
'tab' => array(
'#type' => 'link',
'#title' => t('Unmasquerade'),
'#url' => Url::fromRoute('masquerade.unmasquerade'),
),
'#weight' => 101,
);
}
return $items;
}

html_tag

$color = '#ffeb3b';
$build['html_tag'] = [
'#type' => 'html_tag',
'#tag' => 'p',
'#value' => $this->t('The content area color has been changed to
@code', array('@code' => $color)),
'#attributes' => [
'style' => 'background-color: ' . $color,
],
];

status_messages

$build['status_messages'] = [
'#type' => 'status_messages',
];

view

Renderiza una vista done:

  • '#name' es el machine_name de la vista. Esto se ve en el listado de las views.
  • '#display_id' es el machine_name del display de la vista. Esto se ve cuando editas una view.
$build['view'] = [
  '#prefix' => '<div class="view-comments_recent">',
  '#suffix' => '</div>',
  '#type' => 'view',
  '#name' => 'comments_recent',
  '#display_id' => 'block_1',
  '#embed' => TRUE,
];

Ejemplo de mostrar nodos en una tabla

public function nodes() {

    $query = $this->connection->select('node', 'n');
    $query->join('node_field_data', 'd', 'd.nid = n.nid');
    $query->fields('n', array('nid', 'type'));
    $query->fields('d', ['title']);

    //dpq($query);

    $result = $query->execute();
    $rows = [];

    $build['node_table'] = [
      '#type' => 'table',
      '#header' => ['nid',$this->t('Title'), $this->t('Type'), $this->t('Operations')],
    ];
    foreach ($result as $record){
      $rows[] = [
        $record->nid,
        $record->title,
        $record->type,
        $this->createOperation($record->nid),
      ];
    }

    $build['node_table']['#rows'] = $rows;

    $build['recent_content'] = [
      '#prefix' => '<div class="view-content_recent">',
      '#suffix' => '</div>',
      '#type' => 'view',
      '#name' => 'content_recent',
      '#display_id' => 'block_1',
      '#embed' => TRUE,
    ];

   $build_container = $this->renderChildren($build);

    return $build_container;
}

function renderChildren($son) {
    $build = [
      'container' => [
        '#prefix' => '<div id="mymodule-theming--container">',
        '#suffix' => '</div>',
        '#markup' => $this->t('This is a container div'),
        'son' => [
          $son
        ],
      ],
    ];
    return $build;
}

function createOperation($nid){

    $operations = [
      '#type' => 'dropbutton',
      '#links' => [
        'view' => [
          'title' => $this->t('View'),
          'url' => Url::fromRoute('entity.node.canonical', ['node' => $nid], []),
        ],
        'edit' => [
          'title' => $this->t('Edit'),
          'url' => Url::fromRoute('entity.node.edit_form', ['node' => $nid], []),
        ],
        'delete' => [
          'title' => $this->t('Delete'),
          'url' => Url::fromRoute('entity.node.delete_form', ['node' => $nid], []),
        ],
      ],
    ];
    $operations_rendered = $this->renderer->render($operations);
    return $operations_rendered;
}

Otro ejemplo para mostrar resultados en una tabla sin tanto engorro

inline_template

$build['inline_template'] = [
'#type' => 'inline_template',
'#template' => '<div class="block-filter-text-source">{{ label
}}</div>',
'#context' => [
'label' => $this->t('Lorem Ipsum'),
],
];

Definición de plantillas en módulos

Pasos:

1. Implementar hook_theme

hook_theme($existing, $type, $theme, $path)

donde:

  • $existing tiene info de plantillas actuales
  • $type nos dice si estamos en un módulo, theme, etc.
  • $theme nombre del módulo o tema procesado ahora mismo
  • $path representa el path del módulo o tema procesado ahora mismo

Ejemplo:

/**
 * Implements hook_theme().
 */
function mymodule_theme($existing, $type, $theme, $path) {
  return [
    'mymodule_dimensions' => [
      'variables' => [
        'length' => NULL,
        'width' => NULL,
        'height' => NULL,
        'unit' => 'cm.'
      ],
      'template' => 'mymodule-dimensions',
    ],
  ];
}

donde:

  • variables son las variables usadas en nuestra plantilla tipo #theme
  • template es el nombre de nuestra plantilla (sin extensión .html.twig). Si no se especifica se usaría automáticamente mymodule_dimensions

2. Crear .html.twig

{#
/**
* @file
* Default theme implementation for 'mymodule_dimensions'.
*
* Available variables:
* - length.
* - width.
* - height
* - unit (dafault to cm.)
*/
#}
<span class="item-dimensions">
{% trans %}
    Dimensions (length x width x height): {{ length }} x {{ width }} x
    {{ height }} {{ unit }}
{% endtrans %}
</span>

3. Usar desde un render array el atributo #theme

$build['item_dimensions'] = [
  '#theme' => 'mymodule_dimensions',
  '#length' => 12,
  '#width' => 8,
  '#height' => 24,
];

Más ejemplos en

  • hook_theme() de los módulos del núcleo (.module), y los archivos de plantilla (/templates).
  • El módulo Forum es un buen ejemplo de definición y uso de plantillas.

Funciones de preprocesamiento

Ver D8 Theming Themes > Preprocesses

Para obtener el view mode de una entidad (obteniendo asi su render array sin complicarse la vida):

        $view_builder = \Drupal::entityTypeManager()->getViewBuilder($entity->getEntityTypeId());
        $render_item = $view_builder->view($entity);

Añadir librerías

Pasos:

  1. Crear el fichero css
  2. Definir la librería
mymodule.css:
  version: 1.x
  css:
    theme:
      css/mymodule.css: {}

Con 'theme' estamos estableciendo el peso o nivel del estilo. Los valores posibles, por orden de peso, de menor a mayor, son:

  • base
  • layout
  • component
  • state
  • theme

Uso de librerías

Uso de la libería en un array renderizable


$build['item_dimensions'] = [
  '#theme' => 'mymodule_dimensions',
  '#attached' => [
    'library' => [
      'mymodule/mymodule.css',
    ],
  ],
  '#length' => 12,
  '#width' => 8,
  '#height' => 24,
];

Uso de la librería en una plantilla twig

{{ attach_library('mymodule_theming/mymodule_theming.css') }}

Uso de la librería através de un preprocess

/**
* Implements MODULE_preprocess_HOOK() for focontu_theming_dimensions.
*/
function mymodule_theming_preprocess_mymodule_theming_dimensions(&$variables) {
  $variables['#attached']['library'][] = 'mymodule_theming/mymodule_theming.css';
}

Más info en Drupal.org

Template suggestions

/**
* Implements hook_theme_suggestions_HOOK_alter() for HOOK
* 'mymodule_theming_dimensions'.
*/
function mymodule_theming_theme_suggestions_mymodule_theming_dimensions_alter(array &$suggestions, array $variables) {
  if (\Drupal::currentUser()->isAuthenticated()) {
    $suggestions[] = 'mymodule_theming_dimensions__logged_in';
  }
}

Es MUY IMPORTANTE poner el suggestion con barras bajas. Hay gente que usa esto para no equivocarse

$new_suggestion = str_replace('-', '_', 'mymodule_theming_dimensions__logged_in');
$suggestions[] = $new_suggestion;

MUY IMPORTANTE: Ahora ya podemos usar nuestro nuevo template. Dicho template hay que meterlo al tema (no al módulo) para hacerlo funcionar. El template tendrá signos "-", no contendra "_".

Nombre del fichero será: mymodule-theming-dimensions--logged-in.html.twig

Crear nuevos elementos renderizables

  • Se corresponden con un nuevo #type del elemento renderizable.

  • Para elemtos normales extendemos de RenderElement

  • Para elementos de formularios extendemos de FormElement

  • La clase se crea dentro de /src/Element

Creación

<?php

namespace Drupal\mymodule_theming\Element;

use Drupal\Core\Render\Element\RenderElement;

/**
 * Provides a render element to display a Dimensions item.
 *
 * @RenderElement("mymodule_theming_dimensions")
 */
class MymoduleThemingDimensions extends RenderElement {

  /**
   * Element pre render callback.
   */
  public static function preRendermymoduleThemingDimensions($element) {
    return $element;
  }

  /**
   * {@inheritdoc}
   */
  public function getInfo() {
    $class = get_class($this);
    return [
      '#pre_render' => [
        [$class, 'preRendermymoduleThemingDimensions'],
      ],
      '#length' => NULL,
      '#width' => NULL,
      '#height' => NULL,
      '#unit' => 'cm.',
      '#theme' => 'mymodule_theming_dimensions',
    ];
  }

}

Uso del Elemento creado

$build['item_dimensions_element'] = [
  '#type' => 'mymodule_dimensions',
  '#length' => 11,
  '#width' => 7,
  '#height' => 23,
  '#unit' => 'mm.',
];

Crear extensiones de Twig

Pasos:

  1. Crear la clase
    • Se puede generar el código con drupal generate:twig:extension
<?php

namespace Drupal\mymodule\TwigExtension;

class MymoduleTwigExtension extends \Twig_Extension {
  public function getFunctions() {
    return [
      new \Twig_SimpleFunction('loripsum', [$this, 'loripsum']),
    ];
  }
  public function getFilters() {
    return [
      new \Twig_SimpleFilter('space_replace', [$this, 'spaceReplace']),
    ];
  }
  public function getName() {
    return 'mymodule.twig.extension';
  }
  public function loripsum($length = 50) {
    return
      substr(file_get_contents('http://loripsum.net/api/long/plaintext')
        , 0, $length) . '.';
  }
  public function spaceReplace($string) {
    return str_replace(' ', '-', $string);
  }
}
  1. Crear el servicio
services:
  mymodule.twig.extension:
    class: Drupal\Mymodule\TwigExtension\MymoduleTwigExtension
    tags:
      - { name: twig.extension }

  1. Have fun: {{ loripsum(20)|space_replace }}
⚠️ **GitHub.com Fallback** ⚠️