D8 Theming Modules - pierregermain/MyDrupal GitHub Wiki
- Arrays Renderizables
- Propiedades de los arrays renderizables
- Servicio Renderer
- Elementos Hijos
- Elementos renderizables
- Definición de plantillas en módulos
- Template suggestions
- Crear nuevos elementos renderizables
- Crear extensiones de Twig
- 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,
];
-
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.
Plantilla a ser usada para renderizar
para limitar las etiquetas HTML posibles en una cadena añadida a través de #markup
Funciones a ser ejecutadas antes de renderizar.
Funciones que actúan sobre el html generado
- Servicio: renderer
- Clase Renderer
Una vez inyectado podemos usar: $this->renderer->render($build);
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>
$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], []),
],
],
];
$build['more_link'] = [
'#type' => 'more_link',
'#url' => Url::fromRoute('mymodule_theming.list')
];
- 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;
}
$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,
],
];
$build['status_messages'] = [
'#type' => 'status_messages',
];
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,
];
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
$build['inline_template'] = [
'#type' => 'inline_template',
'#template' => '<div class="block-filter-text-source">{{ label
}}</div>',
'#context' => [
'label' => $this->t('Lorem Ipsum'),
],
];
Pasos:
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
{#
/**
* @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>
$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.
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);
Pasos:
- Crear el fichero css
- 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
$build['item_dimensions'] = [
'#theme' => 'mymodule_dimensions',
'#attached' => [
'library' => [
'mymodule/mymodule.css',
],
],
'#length' => 12,
'#width' => 8,
'#height' => 24,
];
{{ attach_library('mymodule_theming/mymodule_theming.css') }}
/**
* 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
/**
* 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
-
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
<?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',
];
}
}
$build['item_dimensions_element'] = [
'#type' => 'mymodule_dimensions',
'#length' => 11,
'#width' => 7,
'#height' => 23,
'#unit' => 'mm.',
];
- Carpeta a ser usada:
src/TwigExtension
- Extiende de Twig_Extension
Pasos:
- Crear la clase
- Se puede generar el código con
drupal generate:twig:extension
- Se puede generar el código con
<?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);
}
}
- Crear el servicio
services:
mymodule.twig.extension:
class: Drupal\Mymodule\TwigExtension\MymoduleTwigExtension
tags:
- { name: twig.extension }
- Have fun:
{{ loripsum(20)|space_replace }}