Éléments HTML

La classe Nette\Utils\Html est un assistant pour la génération de code HTML qui ne permet pas 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">'

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 plaira le plus. 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&amp;lang=en"></a>'

Attributs de données

Les attributs de données ont 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'; // n'est pas si é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 dans le cas où vous savez que vous passez dans le paramètre une chaîne HTML fiable et sûre.

echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'

echo Html::el('span')->setText('10 < 20');
// '<span>10 &lt; 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 &lt; 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 &lt; 20<br></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 nous voulons travailler avec un tableau de nœuds et que l'élément enveloppant ne nous intéresse pas, nous pouvons créer un soi-disant fragment de document en passant null au lieu du nom de l'élément :

$el = Html::el(null)
	->addHtml('hello<br>')
	->addText('10 < 20')
	->addHtml( Html::el('br') );
// hello<br>10 &lt; 20<br>

Une manière plus rapide de créer un fragment est offerte par les méthodes fromHtml() et fromText() :

$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'

$el = Html::fromText('10 < 20');
echo $el; // '10 &lt; 20'

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"'

Une caractéristique importante est la protection automatique contre le Cross Site Scripting (XSS). Toutes les valeurs d'attributs ou le contenu inséré via setText() ou addText() sont échappés de manière fiable :

echo Html::el('div')
	->title('" onmouseover="bad()')
	->setText('<script>bad()</script>');

// <div title='" onmouseover="bad()'>&lt;script&gt;bad()&lt;/script&gt;</div>

Conversion HTML ↔ texte

Pour la conversion de HTML en texte, vous pouvez utiliser la méthode statique htmlToText() :

echo Html::htmlToText('<span>One &amp; 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. Donc il n'y aura pas de double échappement si par exemple nous affichons l'objet dans un template avec {$el}`

version: 4.0