Éléments HTML

La classe Nette\Utils\Html est une aide pour générer du code HTML qui empêche la vulnérabilité Cross Site Scripting (XSS).

Elle fonctionne de telle manière que ses objets représentent des éléments HTML, nous définissons leurs paramètres et les laissons effectuer le rendu :

$el = Html::el('img');  // crée l'élément <img>.
$el->src = 'image.jpg'; // définit l'attribut src
echo $el;               // imprime '<img src="image.jpg">'

Installation :

composer require nette/utils

Tous les exemples supposent que l'alias de classe suivant est défini :

use Nette\Utils\Html;

Création d'un élément HTML

L'élément est créé à l'aide de la méthode Html::el():

$el = Html::el('img'); // crée l'élément <img>

En plus du nom, vous pouvez saisir d'autres attributs dans la syntaxe HTML :

$el = Html::el('input type=text class="red important"');

Ou les passer comme un tableau associatif au deuxième paramètre :

$el = Html::el('input', [
	'type' => 'text',
	'class' => 'important',
]);

Pour modifier et renvoyer le nom d'un élément :

$el->setName('img');
$el->getName(); // 'img'.
$el->isEmpty(); // true, car <img>est un élément vide.

Attributs HTML

Vous pouvez définir et obtenir des attributs HTML individuels de trois manières, à vous de voir laquelle vous préférez. La première consiste à utiliser 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 façon est d'appeler des méthodes qui, contrairement à la définition des propriétés, peuvent être enchaînées :

$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">

$el->alt(null); // supprime l'attribut

Et la troisième façon est la plus bavarde :

$el = Html::el('img')
	->setAttribute('src', 'image.jpg')
	->setAttribute('alt', 'photo');

echo $el->getAttribute('src'); // 'image.jpg'

$el->removeAttribute('alt');

En vrac, les attributs peuvent être définis avec addAttributes(array $attrs) et supprimés avec removeAttributes(array $attrNames).

La valeur d'un attribut ne doit pas être uniquement une chaîne de caractères, des valeurs logiques pour les attributs logiques peuvent également être utilisées :

$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true;  // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">

Un attribut peut également être un tableau de tokens, qui sont énumérés séparés par des espaces, ce qui convient aux classes CSS, par exemple :

$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null is ignored
$el->class[] = 'top';
echo $el; // '<input class="active top">'

Une alternative est un tableau associatif, où les valeurs indiquent si la clé doit être listé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 la 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 maintenant utilisé les propriétés, mais la même chose peut être faite en utilisant les 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 bavarde :

$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'

Une dernière chose : la méthode href() peut faciliter la composition des paramètres de requête dans une 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 bénéficient d'un support spécial. Comme leurs noms contiennent des traits d'union, l'accès via les propriétés et les méthodes n'est pas aussi élégant, il existe donc une méthode data():

$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // pas très élégant
$el->data('max-size', '500x300'); // c'est élégant
echo $el; // '<input data-max-size="500x300">'.

Si la valeur de l'attribut de données est un tableau, il est automatiquement sérialisé 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

Le contenu interne de l'élément est défini par les méthodes setHtml() ou setText(). N'utilisez la première méthode que si vous savez que vous transmettez de manière fiable une chaîne HTML sécurisée dans le paramètre.

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

echo Html::el('span')->setText('10 < 20');
// '<span>10 &lt; 20</span>'

Inversement, le contenu interne est obtenu par les méthodes getHtml() ou getText(). La seconde supprime les balises de la sortie HTML et convertit les entités HTML en caractères.

echo $el->getHtml(); // '10 &lt; 20'
echo $el->getText(); // '10 < 20'

Nœuds enfants

Le contenu interne d'un élément peut également être un tableau d'enfants. Chacun d'entre eux peut être soit une chaîne de caractères, soit un autre élément Html. Ils sont insérés à 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 façon de créer et d'insérer un nouveau nœud Html:

$el = Html::el('ul')
	->create('li', ['class' => 'first'])
		->setText('hello');
// <ul><li class="first">hello</li></ul>

Vous pouvez travailler avec les nœuds comme s'ils étaient des éléments de tableau. Accédez donc à chacun d'entre eux à l'aide de crochets, comptez-les avec count() et itérez 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é à une position spécifique en utilisant insert(?int $index, $child, bool $replace = false). Si $replace = false, il insère l'élément à la position $index et déplace les autres. Si vous utilisez $index = null, vous ajouterez un élément à la fin.

// insère l'élément en première position et avance les autres
$el->insert(0, Html::el('span'));

Tous les nœuds sont renvoyés par la méthode getChildren() et supprimés par la méthode removeChildren().

Création d'un fragment de document

Si vous souhaitez travailler avec un tableau de nœuds et que vous n'êtes pas intéressé par l'élément d'habillage, vous pouvez créer ce que l'on appelle un fragments 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>

Les méthodes fromHtml() et fromText() offrent un moyen plus rapide de créer un fragment :

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

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

Générer une sortie HTML

La façon la plus simple de générer un élément HTML est d'utiliser echo ou d'envoyer un objet à (string). Vous pouvez également imprimer séparément les balises ouvrantes ou fermantes et les attributs :

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

Une caractéristique importante est la protection automatique contre le Cross Site Scripting (XSS). Toutes les valeurs d'attributs ou le contenu inséré à l'aide de 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

Vous pouvez utiliser la méthode statique htmlToText() pour convertir du HTML en texte :

echo Html::htmlToText('<span>One &amp; Two</span>'); // 'One & Two'

HtmlStringable

L'objet Nette\Utils\Html implémente l'interface Nette\HtmlStringable, que, par exemple, Latte ou les formulaires utilisent pour distinguer les objets qui ont une méthode __toString() qui renvoie du code HTML. Ainsi, le double échappement ne se produit pas si, par exemple, nous imprimons l'objet dans le modèle en utilisant {$el}.

version: 4.0