HTML-Elemente
Die Klasse Nette\Utils\Html ist ein Helfer zur Generierung von HTML-Code, der die Entstehung von Cross-Site-Scripting (XSS)-Schwachstellen verhindert.
Sie funktioniert so, dass ihre Objekte HTML-Elemente darstellen, denen wir Parameter zuweisen und sie dann rendern lassen:
$el = Html::el('img'); // erstellt das Element <img>
$el->src = 'image.jpg'; // setzt das Attribut src
echo $el; // gibt '<img src="image.jpg">' aus
Installation:
composer require nette/utils
Alle Beispiele setzen voraus, dass ein Alias erstellt wurde:
use Nette\Utils\Html;
Erstellung von HTML-Elementen
Ein Element wird mit der Methode Html::el()
erstellt:
$el = Html::el('img'); // erstellt das Element <img>
Neben dem Namen können Sie auch weitere Attribute in HTML-Syntax angeben:
$el = Html::el('input type=text class="red important"');
Oder sie als assoziatives Array im zweiten Parameter übergeben:
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
Ändern und Abrufen des Elementnamens:
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, da <img> ein leeres Element ist
HTML-Attribute
Einzelne HTML-Attribute können auf drei Arten geändert und gelesen werden, es hängt von Ihnen ab, welche Ihnen am besten gefällt. Die erste ist ü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;
Der zweite Weg ist der Aufruf von Methoden, die im Gegensatz zum Setzen von Properties verkettet werden können:
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // Attribut entfernen
Und der dritte Weg ist der ausführlichste:
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
Attribute können massenweise mit addAttributes(array $attrs)
gesetzt und mit
removeAttributes(array $attrNames)
entfernt werden.
Der Wert eines Attributs muss nicht nur ein String sein, es können auch boolesche Werte für logische Attribute verwendet werden:
$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, was beispielsweise für CSS-Klassen nützlich ist:
$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, bei dem die Werte angeben, ob der Schlüssel ausgegeben werden soll:
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
CSS-Stile können in Form von assoziativen Arrays geschrieben werden:
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
Jetzt haben wir Properties verwendet, aber dasselbe kann auch mit Methoden geschrieben werden:
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'
Oder auch 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">'
Noch eine Kleinigkeit zum Schluss: Die Methode href()
kann das Zusammensetzen von Query-Parametern in einer URL
erleichtern:
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Datenattribute
Datenattribute haben spezielle Unterstützung. Da ihre Namen Bindestriche enthalten, ist der Zugriff über Properties und
Methoden nicht so elegant, daher gibt es die 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">'
Wenn der Wert eines Datenattributs ein Array ist, wird er automatisch in JSON serialisiert:
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Inhalt des Elements
Der innere Inhalt eines Elements wird mit den Methoden setHtml()
oder setText()
gesetzt. Verwenden
Sie die erste nur, wenn Sie wissen, dass Sie im Parameter einen zuverlässig sicheren HTML-String übergeben.
echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
Und umgekehrt erhalten wir den inneren Inhalt mit den Methoden getHtml()
oder getText()
. Die zweite
entfernt HTML-Tags aus der Ausgabe und konvertiert HTML-Entitäten in Zeichen.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Untergeordnete Knoten
Der Inhalt eines Elements kann auch ein Array von untergeordneten (children) Knoten sein. Jeder davon kann entweder ein String
oder ein weiteres Html
-Element sein. Wir fügen sie mit addHtml()
oder addText()
ein:
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
Ein weiterer Weg, um einen neuen Html
-Knoten zu erstellen und einzufügen:
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('první');
// <ul><li class="first">první</li></ul>
Mit Knoten kann man wie mit einem Array arbeiten. Das heißt, auf einzelne Knoten mit eckigen Klammern zugreifen, ihre Anzahl
mit count()
zählen und über sie iterieren:
$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
Ein neuer Knoten kann an einer bestimmten Stelle mit insert(?int $index, $child, bool $replace = false)
eingefügt
werden. Wenn $replace = false
, fügt es das Element an der Position $index
ein und verschiebt die
anderen. Wenn $index = null
, wird das Element am Ende hinzugefügt.
// fügt das Element an die erste Position ein und verschiebt die anderen
$el->insert(0, Html::el('span'));
Alle Knoten erhalten wir mit der Methode getChildren()
und entfernen sie mit der Methode
removeChildren()
.
Erstellung eines Dokumentfragments
Wenn wir mit einem Array von Knoten arbeiten möchten und uns das umschließende Element nicht interessiert, können wir ein
sogenanntes Dokumentfragment erstellen, indem wir null
anstelle des Elementnamens übergeben:
$el = Html::el(null)
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// hello<br>10 < 20<br>
Einen schnelleren Weg zur Erstellung eines Fragments bieten die Methoden fromHtml()
und
fromText()
:
$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'
$el = Html::fromText('10 < 20');
echo $el; // '10 < 20'
Generierung der HTML-Ausgabe
Der einfachste Weg, ein HTML-Element auszugeben, ist die Verwendung von echo
oder die Konvertierung des Objekts in
(string)
. Es ist auch möglich, öffnende oder schließende Tags und Attribute separat auszugeben:
$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"'
Ein wichtiges Merkmal ist der automatische Schutz vor Cross Site Scripting (XSS). Alle Attributwerte oder
Inhalte, die über setText()
oder addText()
eingefügt werden, werden zuverlässig escaped:
echo Html::el('div')
->title('" onmouseover="bad()')
->setText('<script>bad()</script>');
// <div title='" onmouseover="bad()'><script>bad()</script></div>
Konvertierung HTML ↔ Text
Zur Konvertierung 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
, mit dem beispielsweise
Latte oder Formulare Objekte unterscheiden, die eine Methode __toString()
haben, die HTML-Code zurückgibt. So kommt
es nicht zu doppeltem Escaping, wenn wir zum Beispiel das Objekt in einer Vorlage mit {$el}
ausgeben.