Elementos HTML
La clase Nette\Utils\Html es una ayuda para generar código HTML que previene la vulnerabilidad Cross Site Scripting (XSS).
Funciona de tal forma que sus objetos representan elementos HTML, establecemos sus parámetros y dejamos que se rendericen:
$el = Html::el('img'); // crea el elemento <img>.
$el->src = 'image.jpg'; // establece el atributo src
echo $el; // imprime '<img src="imagen.jpg">'
Instalación:
composer require nette/utils
Todos los ejemplos asumen que el siguiente alias de clase está definido:
use Nette\Utils\Html;
Creación de un elemento HTML
El elemento se crea utilizando el método Html::el()
:
$el = Html::el('img'); // crea el elemento <img>
Además del nombre, puede introducir otros atributos en la sintaxis HTML:
$el = Html::el('input type=text class="red important"');
O pasarlos como un array asociativo al segundo parámetro:
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
Para cambiar y devolver el nombre de un elemento:
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, as <img> is void element
Atributos HTML
Puedes establecer y obtener atributos HTML individuales de tres maneras, depende de quién te guste más. La primera es a través de las propiedades:
$el->src = 'image.jpg'; // establece el atributo src
echo $el->src; // 'image.jpg'
unset($el->src); // elimina el atributo
// or $el->src = null;
La segunda forma es llamar a métodos que, a diferencia de establecer propiedades, podemos encadenar:
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // elimina el atributo
Y la tercera forma es la más locuaz:
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
En bloque, los atributos pueden fijarse con addAttributes(array $attrs)
y borrarse con
removeAttributes(array $attrNames)
.
El valor de un atributo no tiene por qué ser sólo una cadena, también pueden utilizarse valores lógicos para atributos lógicos:
$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true; // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">
Un atributo también puede ser una matriz de tokens, que se enumeran separados por espacios, lo que es adecuado para las clases CSS, por ejemplo:
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // se ignora null
$el->class[] = 'top';
echo $el; // '<input class="active top">'
Una alternativa es un array asociativo, donde los valores dicen si la clave debe ser listada:
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
Los estilos CSS pueden escribirse en forma de matrices asociativas:
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
Ahora hemos utilizado propiedades, pero se puede hacer lo mismo utilizando los métodos:
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'
O incluso de la forma más locuaz:
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'
Una última cosa: el método href()
puede facilitar la composición de los parámetros de consulta en
una URL:
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Atributos de datos
Los atributos de datos tienen un soporte especial. Debido a que sus nombres contienen guiones, el acceso a través de
propiedades y métodos no es tan elegante, por lo que existe un método data()
:
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // not so elegant
$el->data('max-size', '500x300'); // is elegant
echo $el; // '<input data-max-size="500x300">'
Si el valor del atributo de datos es un array, se serializa automáticamente a JSON:
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Contenido del elemento
El contenido interno del elemento se establece mediante los métodos setHtml()
o setText()
. Utilice
el primero sólo si sabe que está pasando de forma fiable una cadena HTML segura en el parámetro.
echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
Por el contrario, el contenido interno se obtiene mediante los métodos getHtml()
o getText()
. El
segundo elimina las etiquetas de la salida HTML y convierte las entidades HTML en caracteres.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Nodos hijos
El contenido interno de un elemento también puede ser un array de hijos. Cada uno de ellos puede ser una cadena u otro
elemento de Html
. Se insertan utilizando addHtml()
o addText()
:
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
Otra forma de crear e insertar un nuevo nodo Html
:
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('hello');
// <ul><li class="first">hello</li></ul>
Puedes trabajar con nodos como si fueran elementos de un array. Así que accede a los individuales usando corchetes, cuéntalos
con count()
e itera sobre ellos:
$el = Html::el('div');
$el[] = '<b>hello</b>';
$el[] = Html::el('span');
echo $el[1]; // '<span></span>'
foreach ($el as $child) { /* ... */ }
echo count($el); // 2
Se puede insertar un nuevo nodo en una posición específica utilizando
insert(?int $index, $child, bool $replace = false)
. Si $replace = false
, inserta el elemento en la
posición $index
y desplaza los demás. Si $index = null
, añadirá un elemento al final.
// inserta el elemento en la primera posición y avanza los demás
$el->insert(0, Html::el('span'));
Todos los nodos son devueltos por el método getChildren()
y eliminados por el método
removeChildren()
.
Creación de un fragmento de documento
Si desea trabajar con una matriz de nodos y no está interesado en el elemento envolvente, puede crear un llamado fragmento
de documento pasando null
en lugar del nombre del elemento:
$el = Html::el(null)
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// hello<br>10 < 20<br>
Los métodos fromHtml()
y fromText()
ofrecen una forma más rápida de crear un fragmento:
$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'
$el = Html::fromText('10 < 20');
echo $el; // '10 < 20'
Generar salida HTML
La forma más sencilla de generar un elemento HTML es utilizar echo
o lanzar un objeto a (string)
.
También puede imprimir etiquetas de apertura o cierre y atributos por separado:
$el = Html::el('div class=header')->setText('hello');
echo $el; // '<div class="header"></div>'
$s = (string) $el; // '<div class="header">hello</div>'
$s = $el->toHtml(); // '<div class="header">hello</div>'
$s = $el->toText(); // 'hello'
echo $el->startTag(); // '<div class="header">'
echo $el->endTag(); // '</div>'
echo $el->attributes(); // 'class="header"'
Una característica importante es la protección automática contra Cross Site Scripting (XSS). Todos los valores de
atributos o contenidos insertados mediante setText()
o addText()
se escapan de forma fiable:
echo Html::el('div')
->title('" onmouseover="bad()')
->setText('<script>bad()</script>');
// <div title='" onmouseover="bad()'><script>bad()</script></div>
Conversión HTML ↔ Texto
Puede utilizar el método estático htmlToText()
para convertir HTML en texto:
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
El objeto Nette\Utils\Html
implementa la interfaz Nette\HtmlStringable
, que, por ejemplo, Latte
o forms utilizan para distinguir los objetos que tienen un método __toString()
que devuelve código HTML. Así, el
doble escape no se produce si, por ejemplo, imprimimos el objeto en la plantilla utilizando {$el}
.