Éléments HTML
La classe Nette\Utils\Html est un assistant pour la génération de code HTML qui empêche l'apparition de vulnérabilités Cross Site Scripting (XSS).
Elle fonctionne de telle sorte que ses objets représentent des éléments HTML, auxquels nous définissons des paramètres et les laissons s'afficher :
$el = Html::el('img'); // crée l'élément <img>
$el->src = 'image.jpg'; // définit l'attribut src
echo $el; // affiche '<img src="image.jpg">'
Vous pouvez remplir le corps d'un élément avec du texte et d'autres éléments à l'aide de la méthode
add(). Le texte est échappé automatiquement, les éléments sont insérés tels quels :
echo Html::el('div')->add(
'Hello ',
Html::el('b')->setText('world'),
);
// '<div>Hello <b>world</b></div>'
Installation :
composer require nette/utils
Tous les exemples supposent qu'un alias a été créé :
use Nette\Utils\Html;
Création d'un élément HTML
Nous créons un élément avec la méthode Html::el() :
$el = Html::el('img'); // crée l'élément <img>
En plus du nom, vous pouvez spécifier d'autres attributs en syntaxe HTML :
$el = Html::el('input type=text class="red important"');
Ou les passer sous forme de tableau associatif comme second paramètre :
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
Modification et retour du nom de l'élément :
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, car <img> est un élément vide
Attributs HTML
Nous pouvons modifier et lire les attributs HTML individuels de trois manières, cela dépend de vous laquelle vous préférez. La première est via les propriétés :
$el->src = 'image.jpg'; // définit l'attribut src
echo $el->src; // 'image.jpg'
unset($el->src); // supprime l'attribut
// ou $el->src = null;
La deuxième voie est l'appel de méthodes, que nous pouvons enchaîner contrairement à la définition via propriétés :
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // suppression de l'attribut
Et la troisième manière est la plus verbeuse :
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
Les attributs peuvent être définis en masse à l'aide de addAttributes(array $attrs) et supprimés à l'aide de
removeAttributes(array $attrNames).
La valeur de l'attribut ne doit pas être seulement une chaîne, il est possible d'utiliser aussi des valeurs logiques pour les attributs logiques :
$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true; // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">
L'attribut peut aussi être un tableau de valeurs, qui s'affichent séparées par des espaces, ce qui est utile par exemple pour les classes CSS :
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null est ignoré
$el->class[] = 'top';
echo $el; // '<input class="active top">'
L'alternative est un tableau associatif, où les valeurs indiquent si la clé doit être affichée :
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
Les styles CSS peuvent être écrits sous forme de tableaux associatifs :
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
Nous avons utilisé les propriétés maintenant, mais la même chose peut être écrite à l'aide de méthodes :
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'
Ou même de la manière la plus verbeuse :
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'
Encore un petit détail pour finir : la méthode href() peut faciliter l'assemblage des paramètres de requête
dans l'URL :
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Attributs de données
Les attributs de données bénéficient d'un support spécial. Parce que leurs noms contiennent des tirets, l'accès via
propriétés et méthodes n'est pas si élégant, c'est pourquoi la méthode data() existe :
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // pas très élégant
$el->data('max-size', '500x300'); // est élégant
echo $el; // '<input data-max-size="500x300">'
Si la valeur de l'attribut de données est un tableau, elle est automatiquement sérialisée en JSON :
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Contenu de l'élément
Nous définissons le contenu interne de l'élément avec les méthodes setHtml() ou setText().
Utilisez la première seulement si vous savez que vous passez une chaîne HTML fiable et sûre dans le paramètre.
echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
Et inversement, nous obtenons le contenu interne avec les méthodes getHtml() ou getText(). La
seconde supprime les balises HTML de la sortie et convertit les entités HTML en caractères.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Nœuds enfants
L'intérieur de l'élément peut aussi être un tableau de nœuds enfants (children). Chacun d'eux peut être soit une chaîne,
soit un autre élément Html. Nous les insérons à l'aide de addHtml() ou addText() :
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
La méthode add() insère plusieurs enfants d'un coup. Les chaînes sont échappées comme
avec addText(), les objets Html sont insérés tels quels et les valeurs null sont
ignorées, ce qui est pratique pour du contenu conditionnel. Enveloppez dans Html::html() une chaîne dont vous êtes
sûr qu'elle est du HTML sain :
$el = Html::el('span')->add(
'10 < 20',
Html::el('br'),
Html::html('hello<br>'),
$showNote ? Html::el('small')->setText('note') : null,
);
// <span>10 < 20<br>hello<br><small>note</small></span>
Une autre manière de créer et d'insérer un nouveau nœud Html :
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('premier');
// <ul><li class="first">premier</li></ul>
On peut travailler avec les nœuds de la même manière que s'il s'agissait d'un tableau. C'est-à-dire accéder à chacun
d'eux à l'aide de crochets, les compter à l'aide de count() et itérer sur eux :
$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
Un nouveau nœud peut être inséré à un endroit spécifique à l'aide de
insert(?int $index, $child, bool $replace = false). Si $replace = false, insère l'élément à la
position $index et décale les autres. Si $index = null, ajoute l'élément à la fin.
// insère l'élément à la première position et décale les autres
$el->insert(0, Html::el('span'));
Nous obtenons tous les nœuds avec la méthode getChildren() et les supprimons avec la méthode
removeChildren().
Création d'un fragment de document
Si vous voulez travailler avec un ensemble de nœuds sans vous soucier d'un élément enveloppant, vous
pouvez créer un fragment de document. Il ne rend que ses enfants, sans balise propre. La méthode
fragment() le crée et le remplit d'enfants en un seul appel, selon les mêmes règles que add() :
echo Html::fragment(
Html::el('strong')->setText('hello'),
'10 < 20',
Html::el('br'),
);
// <strong>hello</strong>10 < 20<br>
Un fragment au contenu uniquement textuel ou uniquement HTML se crée avec les méthodes
text() et html() :
echo Html::text('10 < 20'); // '10 < 20'
echo Html::html('hello<br>'); // 'hello<br>'
Si vous devez prendre en charge des versions antérieures à 4.1.5, créez un fragment en passant null au lieu du
nom de l'élément et remplissez-le avec addHtml() et addText(). À la place de text() et
html(), ces versions offrent les méthodes fromText() et fromHtml(), qui fonctionnent
encore mais sont dépréciées :
$el = Html::el(null)
->addHtml('hello<br>')
->addText('10 < 20');
// hello<br>10 < 20
echo Html::fromText('10 < 20'); // '10 < 20'
echo Html::fromHtml('hello<br>'); // 'hello<br>'
Génération de la sortie HTML
La manière la plus simple d'afficher un élément HTML est d'utiliser echo ou de convertir l'objet en
(string). Il est aussi possible d'afficher séparément les balises ouvrantes ou fermantes et les attributs :
$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"'
La méthode render(?int $indent = null) propose un affichage soigné. Si vous lui passez un niveau d'indentation,
la sortie est joliment indentée sur plusieurs lignes :
echo $el->render(0); // retourne du HTML indenté
Une caractéristique importante est la protection automatique contre le Cross Site Scripting (XSS). Toutes les valeurs
d'attributs et tout contenu inséré via setText(), addText(), add() ou
fragment() sont échappés de manière fiable :
echo Html::el('div')
->title('"
->setText('<script>bad()</script>');
// <div title='"
Conversion HTML ↔ texte
Pour la conversion de HTML en texte, vous pouvez utiliser la méthode statique htmlToText() :
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
L'objet Nette\Utils\Html implémente l'interface Nette\HtmlStringable, par laquelle Latte ou les
formulaires, par exemple, distinguent les objets qui ont une méthode __toString() retournant du code HTML. Ainsi, il
n'y aura pas de double échappement si par exemple nous affichons l'objet dans un template avec {$el}.