HTML-Elemente
Die Klasse Nette\Utils\Html ist ein Helfer zum Erzeugen von HTML-Code, der dabei hilft, Sicherheitslücken durch Cross-Site Scripting (XSS) zu verhindern.
Sie funktioniert so, dass ihre Objekte HTML-Elemente repräsentieren; Sie setzen deren Parameter und rendern sie anschließend:
$el = Html::el('img'); // erzeugt das Element <img>
$el->src = 'image.jpg'; // setzt das Attribut src
echo $el; // gibt '<img src="image.jpg">' aus
Den Körper eines Elements füllen Sie mit der Methode add() mit Text und weiteren Elementen.
Text wird automatisch escapt, Elemente werden so eingefügt, wie sie sind:
echo Html::el('div')->add(
'Hallo ',
Html::el('b')->setText('Welt'),
);
// '<div>Hallo <b>Welt</b></div>'
Installation:
composer require nette/utils
Alle Beispiele setzen voraus, dass dieser Klassen-Alias definiert ist:
use Nette\Utils\Html;
Erzeugen eines HTML-Elements
Ein Element wird mit der Methode Html::el() erzeugt:
$el = Html::el('img'); // erzeugt das Element <img>
Neben dem Namen können Sie in HTML-Syntax auch weitere Attribute angeben:
$el = Html::el('input type=text class="red important"');
Oder Sie übergeben sie als assoziatives Array im zweiten Parameter:
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
So ändern und lesen Sie den Namen des Elements:
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, denn <img> ist ein leeres Element
HTML-Attribute
Die einzelnen HTML-Attribute lassen sich auf drei Arten setzen und auslesen; welche Ihnen lieber ist, bleibt Ihnen überlassen. Die erste geht über Properties:
$el->src = 'image.jpg'; // setzt das Attribut src
echo $el->src; // 'image.jpg'
unset($el->src); // entfernt das Attribut
// oder $el->src = null;
Die zweite Art sind Methodenaufrufe, die sich anders als das Setzen von Properties verketten lassen:
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // entfernt das Attribut
Und die dritte Art ist die ausführlichste:
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
Attribute lassen sich mit addAttributes(array $attrs) gesammelt setzen und mit
removeAttributes(array $attrNames) gesammelt entfernen.
Der Wert eines Attributs muss nicht nur ein String sein; für boolesche Attribute lassen sich boolesche Werte verwenden:
$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true; // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">
Ein Attribut kann auch ein Array von Werten sein, die durch Leerzeichen getrennt ausgegeben werden. Das ist zum Beispiel für CSS-Klassen nützlich:
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null wird ignoriert
$el->class[] = 'top';
echo $el; // '<input class="active top">'
Eine Alternative ist ein assoziatives Array, dessen Werte angeben, ob der Schlüssel enthalten sein soll:
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
CSS-Stile lassen sich als assoziative Arrays schreiben:
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color:green;display:block">'
Bisher haben wir Properties verwendet, dasselbe lässt sich aber auch mit Methoden erreichen:
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color:green;display:block">'
Oder sogar auf die ausführlichste Weise:
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color:green;display:block">'
Eine letzte Kleinigkeit: Die Methode href() kann das Zusammensetzen von Query-Parametern einer URL
vereinfachen:
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Data-Attribute
Data-Attribute werden besonders unterstützt. Weil ihre Namen Bindestriche enthalten, ist der Zugriff über Properties und
Methoden nicht so elegant, deshalb gibt es die eigene Methode data():
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // nicht so elegant
$el->data('max-size', '500x300'); // ist elegant
echo $el; // '<input data-max-size="500x300">'
Ist der Wert eines Data-Attributs ein Array, wird er automatisch nach JSON serialisiert:
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Inhalt des Elements
Den inneren Inhalt des Elements setzen Sie mit den Methoden setHtml() oder setText(). Die erste
verwenden Sie nur dann, wenn Sie sicher sind, dass der Parameter einen verlässlich sicheren HTML-String enthält.
echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
Umgekehrt lässt sich der innere Inhalt mit den Methoden getHtml() oder getText() auslesen. Die
zweite entfernt HTML-Tags aus dem Inhalt und wandelt HTML-Entities zurück in Zeichen.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Kindknoten
Der innere Inhalt eines Elements kann auch ein Array von Kindknoten sein. Jedes Kind kann entweder ein String oder ein weiteres
Html-Objekt sein. Hinzugefügt werden sie mit addHtml() oder addText():
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
Die Methode add() fügt mehrere Kinder auf einmal ein. Strings werden genauso escapt wie bei
addText(), Html-Objekte werden so eingefügt, wie sie sind, und null-Werte werden
übersprungen, was sich für bedingte Inhalte anbietet. Einen String, der verlässlich sicheres HTML ist, verpacken Sie in
Html::html():
$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>
Eine weitere Möglichkeit, einen neuen Html-Knoten zu erzeugen und einzufügen:
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('erster');
// <ul><li class="first">erster</li></ul>
Mit den Knoten lässt sich arbeiten, als wären sie Array-Elemente. Sie greifen also über eckige Klammern auf einzelne Knoten
zu, zählen sie mit count() und iterieren über sie:
$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
Einen neuen Knoten fügen Sie mit insert(?int $index, $child, bool $replace = false) an einer bestimmten Position
ein. Ist $replace = false, wird das Element an der Position $index eingefügt und die übrigen werden
verschoben. Ist $index = null, wird das Element ans Ende angehängt.
// fügt das Element an der ersten Position ein und verschiebt die übrigen
$el->insert(0, Html::el('span'));
Alle Knoten liefert die Methode getChildren(), entfernen lassen sie sich mit der Methode
removeChildren().
Erzeugen eines Dokumentfragments
Wenn Sie mit einer Menge von Knoten arbeiten wollen und kein umschließendes Element brauchen, können Sie
ein Dokumentfragment erzeugen. Es rendert nur seine Kinder, ohne einen eigenen Tag. Die Methode fragment()
erzeugt es und füllt es in einem einzigen Aufruf mit Kindern, nach denselben Regeln wie add():
echo Html::fragment(
Html::el('strong')->setText('hello'),
'10 < 20',
Html::el('br'),
);
// <strong>hello</strong>10 < 20<br>
Ein Fragment mit ausschließlich Text- oder ausschließlich HTML-Inhalt erzeugen die Methoden
text() und html():
echo Html::text('10 < 20'); // '10 < 20'
echo Html::html('hello<br>'); // 'hello<br>'
Wenn Sie Versionen vor 4.1.5 unterstützen müssen, erzeugen Sie ein Fragment, indem Sie statt eines Elementnamens
null übergeben, und füllen es mit addHtml() und addText(). Statt text() und
html() bieten diese Versionen die Methoden fromText() und fromHtml(), die weiterhin
funktionieren, aber veraltet sind:
$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>'
Erzeugen der HTML-Ausgabe
Am einfachsten geben Sie ein HTML-Element mit echo aus oder casten das Objekt nach (string). Sie
können auch den öffnenden Tag, den schließenden Tag und die Attribute getrennt ausgeben:
$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"'
Die Methode render(?int $indent = null) bietet eine hübsche Formatierung. Wenn Sie eine Einrückungsebene
übergeben, wird die Ausgabe über mehrere Zeilen sauber eingerückt:
echo $el->render(0); // gibt eingerücktes HTML zurück
Eine wichtige Eigenschaft ist der automatische Schutz vor Cross-Site Scripting (XSS). Alle Attributwerte und alle
über setText(), addText(), add() oder fragment() eingefügten Inhalte werden
verlässlich escapt:
echo Html::el('div')
->title('" onmouseover="bad()')
->setText('<script>bad()</script>');
// <div title='" onmouseover="bad()'><script>bad()</script></div>
Umwandlung HTML ↔ Text
Zur Umwandlung von HTML in Text können Sie die statische Methode htmlToText() verwenden:
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
Das Objekt Nette\Utils\Html implementiert das Interface Nette\HtmlStringable. Latte und Forms nutzen
dieses Interface zum Beispiel, um Objekte zu erkennen, deren Methode __toString() HTML-Code zurückgibt. Das
verhindert doppeltes Escaping, wenn Sie das Objekt etwa im Template mit {$el} ausgeben.