Elementi HTML
La classe Nette\Utils\Html è un aiutante per la generazione di codice HTML che impedisce la vulnerabilità Cross Site Scripting (XSS).
Funziona in modo tale che i suoi oggetti rappresentano elementi HTML, ai quali impostiamo i parametri e li facciamo renderizzare:
$el = Html::el('img'); // crea l'elemento <img>
$el->src = 'image.jpg'; // imposta l'attributo src
echo $el; // stampa '<img src="image.jpg">'
Installazione:
composer require nette/utils
Tutti gli esempi presuppongono la creazione di un alias:
use Nette\Utils\Html;
Creazione di un elemento HTML
Creiamo un elemento con il metodo Html::el()
:
$el = Html::el('img'); // crea l'elemento <img>
Oltre al nome, puoi specificare anche altri attributi nella sintassi HTML:
$el = Html::el('input type=text class="red important"');
Oppure passarli come array associativo nel secondo parametro:
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
Modifica e restituzione del nome dell'elemento:
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, poiché <img> è un elemento vuoto
Attributi HTML
Possiamo modificare e leggere i singoli attributi HTML in tre modi, dipende da te quale ti piacerà di più. Il primo è tramite le proprietà:
$el->src = 'image.jpg'; // imposta l'attributo src
echo $el->src; // 'image.jpg'
unset($el->src); // rimuove l'attributo
// o $el->src = null;
Il secondo modo è chiamare metodi, che, a differenza dell'impostazione delle proprietà, possiamo concatenare:
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // rimozione dell'attributo
E il terzo modo è il più prolisso:
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
È possibile impostare attributi in blocco usando addAttributes(array $attrs)
e rimuoverli usando
removeAttributes(array $attrNames)
.
Il valore di un attributo non deve essere solo una stringa, è possibile utilizzare anche valori booleani per attributi booleani:
$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true; // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">
Un attributo può anche essere un array di valori, che verranno stampati separati da spazi, il che è utile ad esempio per le classi CSS:
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null viene ignorato
$el->class[] = 'top';
echo $el; // '<input class="active top">'
Un'alternativa è un array associativo, dove i valori indicano se la chiave deve essere stampata:
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
Gli stili CSS possono essere scritti sotto forma di array associativi:
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
Ora abbiamo usato le proprietà, ma la stessa cosa può essere scritta usando i metodi:
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'
O anche nel modo più prolisso:
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'
Un ultimo piccolo dettaglio: il metodo href()
può facilitare la composizione dei parametri di query nell'URL:
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Attributi data
Gli attributi data hanno un supporto speciale. Poiché i loro nomi contengono trattini, l'accesso tramite proprietà e metodi
non è così elegante, quindi esiste il metodo data()
:
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // non è così elegante
$el->data('max-size', '500x300'); // è elegante
echo $el; // '<input data-max-size="500x300">'
Se il valore di un attributo data è un array, viene automaticamente serializzato in JSON:
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Contenuto dell'elemento
Impostiamo il contenuto interno dell'elemento con i metodi setHtml()
o setText()
. Usa il primo solo
se sai che stai passando una stringa HTML sicuramente sicura nel parametro.
echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
E viceversa, otteniamo il contenuto interno con i metodi getHtml()
o getText()
. Il secondo rimuove
i tag HTML dall'output e converte le entità HTML in caratteri.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Nodi figli
L'interno dell'elemento può anche essere un array di nodi figli (children). Ognuno di essi può essere una stringa o un altro
elemento Html
. Li inseriamo usando addHtml()
o addText()
:
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
Un altro modo per creare e inserire un nuovo nodo Html
:
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('primo');
// <ul><li class="first">primo</li></ul>
È possibile lavorare con i nodi come se fossero un array. Cioè, accedere a ciascuno di essi usando parentesi quadre,
contarli usando count()
e iterare su di essi:
$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
È possibile inserire un nuovo nodo in una posizione specifica usando
insert(?int $index, $child, bool $replace = false)
. Se $replace = false
, inserisce l'elemento nella
posizione $index
e sposta gli altri. Se $index = null
, aggiunge l'elemento alla fine.
// inserisce l'elemento nella prima posizione e sposta gli altri
$el->insert(0, Html::el('span'));
Otteniamo tutti i nodi con il metodo getChildren()
e li rimuoviamo con il metodo
removeChildren()
.
Creazione di un frammento di documento
Se vogliamo lavorare con un array di nodi e non ci interessa l'elemento contenitore, possiamo creare un cosiddetto document
fragment passando null
invece del nome dell'elemento:
$el = Html::el(null)
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// hello<br>10 < 20<br>
Un modo più veloce per creare un frammento è offerto dai metodi fromHtml()
e fromText()
:
$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'
$el = Html::fromText('10 < 20');
echo $el; // '10 < 20'
Generazione dell'output HTML
Il modo più semplice per stampare un elemento HTML è usare echo
o convertire l'oggetto in
(string)
. È anche possibile stampare separatamente i tag di apertura o chiusura e gli attributi:
$el = Html::el('div class=header')->setText('hello');
echo $el; // '<div class="header">hello</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 caratteristica importante è la protezione automatica contro il Cross Site Scripting (XSS). Tutti i valori degli
attributi o il contenuto inserito tramite setText()
o addText()
vengono escapati in modo
affidabile:
echo Html::el('div')
->title('" onmouseover="bad()')
->setText('<script>bad()</script>');
// <div title='" onmouseover="bad()'><script>bad()</script></div>
Conversione HTML ↔ testo
Per convertire HTML in testo, puoi utilizzare il metodo statico htmlToText()
:
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
L'oggetto Nette\Utils\Html
implementa l'interfaccia Nette\HtmlStringable
, con cui, ad esempio, Latte
o i form distinguono gli oggetti che hanno un metodo __toString()
che restituisce codice HTML. Quindi non si
verifica un doppio escaping se, ad esempio, stampiamo l'oggetto in un template usando {$el}
.