Elementos HTML
A classe Nette\Utils\Html é uma ajuda para gerar código HTML que evita a vulnerabilidade de Cross Site Scripting (XSS).
Ela funciona de tal forma que seus objetos representam elementos HTML, nós definimos seus parâmetros e os deixamos renderizar:
$el = Html::el('img'); // cria <img> elemento
$el->src = 'image.jpg'; // define o atributo src
echo $el; // imprime '<img src="image.jpg">'
Instalação:
composer require nette/utils
Todos os exemplos assumem que a seguinte classe está definida:
use Nette\Utils\Html;
Criação de um Elemento HTML
O elemento é criado usando o método Html::el()
:
$el = Html::el('img'); // cria <img> elemento
Além do nome, você pode inserir outros atributos na sintaxe HTML:
$el = Html::el('input type=text class="red important"');
Ou passe-as como uma matriz associativa para o segundo parâmetro:
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
Para mudar e devolver um nome de elemento:
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, as <img> is void element
Atributos HTML
Você pode definir e obter atributos HTML individuais de três maneiras, cabe a você quem você mais gosta. A primeira é através das propriedades:
$el->src = 'image.jpg'; // define o atributo src
echo $el->src; // 'image.jpg'
unset($el->src); // remove atributo
// ou $el->src = null;
A segunda maneira é chamar métodos que, em contraste com a definição de propriedades, podemos encadear juntos:
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // remove atributo
E a terceira maneira é a mais faladora:
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
Em grandes quantidades, os atributos podem ser definidos com addAttributes(array $attrs)
e excluídos com
removeAttributes(array $attrNames)
.
O valor de um atributo não tem que ser apenas uma string, também podem ser usados 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">
Um atributo também pode ser um conjunto de fichas, que são listadas separadas por espaços, o que é adequado para classes CSS, por exemplo:
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null is ignored
$el->class[] = 'top';
echo $el; // '<input class="active top">'
Uma alternativa é uma matriz associativa, onde os valores dizem se a chave deve ser listada:
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
Os estilos CSS podem ser escritos sob a forma de matrizes associativas:
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
Agora usamos propriedades, mas o mesmo pode ser feito com os métodos:
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'
Ou mesmo da maneira mais faladora:
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'
Uma última coisa: o método href()
pode facilitar a composição de parâmetros de consulta em uma URL:
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Atributos de dados
Os atributos de dados têm suporte especial. Como seus nomes contêm hífens, o acesso através de propriedades e métodos
não é tão elegante, por isso existe um método data()
:
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // não tão elegante
$el->data('max-size', '500x300'); // é elegante
echo $el; // '<input data-max-size="500x300">'
Se o valor do atributo de dados for um array, ele é automaticamente serializado para o JSON:
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Conteúdo do Elemento
O conteúdo interno do elemento é definido pelos métodos setHtml()
ou setText()
. Use o primeiro
somente se você souber que está passando com segurança uma string HTML segura no 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 outro lado, o conteúdo interno é obtido pelos métodos getHtml()
ou getText()
. O segundo
remove as tags da saída HTML e converte as entidades HTML em caracteres.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Nodos Infantis
O conteúdo interno de um elemento também pode ser um conjunto de crianças. Cada um deles pode ser um fio ou outro elemento
Html
. Eles são inseridos usando addHtml()
ou addText()
:
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
Outra maneira de criar e inserir um novo nódulo Html
:
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('hello');
// <ul><li class="first">hello</li></ul>
Você pode trabalhar com nós como se fossem itens de matriz. Portanto, acesse os individuais usando colchetes, conte-os com
count()
e itere sobre eles:
$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
Um novo nó pode ser inserido em uma posição específica usando
insert(?int $index, $child, bool $replace = false)
. Se $replace = false
, ele insere o elemento na
posição $index
e move os outros. Se $index = null
, ele anexará um elemento no final.
// insere o elemento na primeira posição e avança os outros
$el->insert(0, Html::el('span'));
Todos os nós são devolvidos pelo método getChildren()
e removidos pelo método
removeChildren()
.
Criação de um fragmento de documento
Se você quiser trabalhar com um conjunto de nós e não estiver interessado no elemento de embalagem, você pode criar um
fragmento chamado documento passando null
em vez do nome do elemento:
$el = Html::el(null)
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// hello<br>10 < 20<br>
Os métodos fromHtml()
e fromText()
oferecem uma maneira mais rápida de criar um fragmento:
$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'
$el = Html::fromText('10 < 20');
echo $el; // '10 < 20'
Geração de saída HTML
A maneira mais fácil de gerar um elemento HTML é usar echo
ou lançar um objeto para (string)
.
Você também pode imprimir tags e atributos de abertura ou fechamento separadamente:
$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"'
Uma característica importante é a proteção automática contra o Cross Site Scripting (XSS). Todos os valores de
atributos ou conteúdos inseridos usando setText()
ou addText()
escapam de forma confiável:
echo Html::el('div')
->title('" onmouseover="bad()')
->setText('<script>bad()</script>');
// <div title='" onmouseover="bad()'><script>bad()</script></div>
Conversão HTML ↔ Texto
Você pode usar o método estático htmlToText()
para converter HTML em texto:
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
O objeto Nette\Utils\Html
implementa a interface Nette\HtmlStringable
, que, por exemplo, Latte ou
formulários usam para distinguir objetos que têm um método __toString()
que retorna o código HTML. Assim, a
dupla fuga não ocorre se, por exemplo, imprimirmos o objeto no modelo usando {$el}
.