Elementos HTML
A classe Nette\Utils\Html é um auxiliar para gerar código HTML que previne a vulnerabilidade de Cross Site Scripting (XSS).
Funciona de tal forma que seus objetos representam elementos HTML, aos quais definimos parâmetros e os deixamos renderizar:
$el = Html::el('img'); // cria o elemento <img>
$el->src = 'image.jpg'; // define o atributo src
echo $el; // imprime '<img src="image.jpg">'
Instalação:
composer require nette/utils
Todos os exemplos pressupõem a criação de um alias:
use Nette\Utils\Html;
Criação de elementos HTML
Criamos um elemento usando o método Html::el():
$el = Html::el('img'); // cria o elemento <img>
Além do nome, você também pode especificar outros atributos na sintaxe HTML:
$el = Html::el('input type=text class="red important"');
Ou passá-los como um array associativo no segundo parâmetro:
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
Alterando e retornando o nome do elemento:
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, pois <img> é um elemento vazio
Atributos HTML
Podemos alterar e ler atributos HTML individuais de três maneiras; depende de você qual delas prefere. A primeira é através de propriedades:
$el->src = 'image.jpg'; // define o atributo src
echo $el->src; // 'image.jpg'
unset($el->src); // remove o atributo
// ou $el->src = null;
A segunda maneira é chamando métodos, que, ao contrário da definição de propriedades, podemos encadear:
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="foto">
$el->alt(null); // remoção do atributo
E a terceira maneira é a mais verbosa:
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
Atributos podem ser definidos em massa usando addAttributes(array $attrs) e removidos usando
removeAttributes(array $attrNames).
O valor de um atributo não precisa ser apenas uma string; valores booleanos também podem ser usados 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 array de valores, que serão impressos separados por espaços, o que é útil, por exemplo, para classes CSS:
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null é ignorado
$el->class[] = 'top';
echo $el; // '<input class="active top">'
Uma alternativa é um array associativo, onde os valores indicam se a chave deve ser impressa:
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
Estilos CSS podem ser escritos na forma de arrays associativos:
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
Até agora usamos propriedades, mas o mesmo pode ser escrito usando 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 verbosa:
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'
Um pequeno detalhe para concluir: o método href() pode facilitar a composição de parâmetros de consulta
na URL:
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Atributos de dados
Atributos de dados têm suporte especial. Como seus nomes contêm hífens, o acesso via propriedades e métodos não é tão
elegante, por isso existe o 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 de um atributo de dados for um array, ele é automaticamente serializado para JSON:
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Conteúdo do elemento
Definimos o conteúdo interno do elemento usando os métodos setHtml() ou setText(). Use o primeiro
apenas se souber que está passando uma string HTML confiavelmente segura no parâmetro.
echo Html::el('span')->setHtml('olá<br>');
// '<span>olá<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
E, inversamente, obtemos o conteúdo interno usando os métodos getHtml() ou getText(). O segundo
remove tags HTML da saída e converte entidades HTML em caracteres.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Nós filhos
O interior de um elemento também pode ser um array de nós filhos (children). Cada um deles pode ser uma string ou outro
elemento Html. Nós os inserimos usando addHtml() ou addText():
$el = Html::el('span')
->addHtml('olá<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>olá<br>10 < 20<br></span>
Outra maneira de criar e inserir um novo nó Html:
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('primeiro');
// <ul><li class="first">primeiro</li></ul>
É possível trabalhar com nós da mesma forma que com arrays. Ou seja, acessar nós individuais usando colchetes, contá-los
usando count() e iterar sobre eles:
$el = Html::el('div');
$el[] = '<b>olá</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 desloca os outros. Se $index = null, ele adiciona o elemento ao final.
// insere o elemento na primeira posição e desloca os outros
$el->insert(0, Html::el('span'));
Obtemos todos os nós usando o método getChildren() e os removemos usando o método
removeChildren().
Criação de fragmento de documento
Se quisermos trabalhar com um array de nós e não nos importarmos com o elemento envolvente, podemos criar um chamado
fragmento de documento passando null em vez do nome do elemento:
$el = Html::el(null)
->addHtml('olá<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// olá<br>10 < 20<br>
Uma maneira mais rápida de criar um fragmento é oferecida pelos métodos fromHtml() e
fromText():
$el = Html::fromHtml('olá<br>');
echo $el; // 'olá<br>'
$el = Html::fromText('10 < 20');
echo $el; // '10 < 20'
Geração de saída HTML
A maneira mais simples de imprimir um elemento HTML é usar echo ou converter o objeto para
(string). Também é possível imprimir separadamente as tags de abertura ou fechamento e os atributos:
$el = Html::el('div class=header')->setText('olá');
echo $el; // '<div class="header">olá</div>'
$s = (string) $el; // '<div class="header">olá</div>'
$s = $el->toHtml(); // '<div class="header">olá</div>'
$s = $el->toText(); // 'olá'
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 Cross Site Scripting (XSS). Todos os valores de
atributos ou conteúdo inserido via setText() ou addText() são escapados 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
Para converter HTML em texto, você pode usar o método estático htmlToText():
echo Html::htmlToText('<span>Um & Dois</span>'); // 'Um & Dois'
HtmlStringable
O objeto Nette\Utils\Html implementa a interface Nette\HtmlStringable, que, por exemplo, o Latte ou
os formulários usam para distinguir objetos que possuem um método __toString() retornando código HTML. Assim, não
ocorrerá dupla escapagem se, por exemplo, imprimirmos o objeto em um template usando {$el}.