Елементи HTML
Клас Nette\Utils\Html – це помічник для генерації HTML-коду, який не допускає вразливості Cross Site Scripting (XSS).
Принцип його роботи полягає в тому, що його об'єкти – це елементи HTML, яким ми задаємо параметри і даємо змогу їх відтворювати:
$el = Html::el('img'); // створює елемент <img>
$el->src = 'image.jpg'; // встановлює атрибут src
echo $el; // друкує '<img src="image.jpg">'
Встановлення:
composer require nette/utils
У всіх прикладах передбачається, що псевдонім уже створено:
use Nette\Utils\Html;
Створення елемента HTML
Створіть елемент, використовуючи метод Html::el()
:
$el = Html::el('img'); // створює елемент <img>
Крім імені, ви можете вказати інші атрибути в синтаксисі HTML:
$el = Html::el('input type=text class="red important"');
Або передайте їх як асоціативне поле з другим параметром:
$el = Html::el('input', [
'type' => 'text',
'class' => 'important',
]);
Зміна та повернення імені елемента:
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, оскільки <img> є порожнім елементом
Атрибути HTML
Існує три способи зміни та читання окремих атрибутів HTML, і ви самі вирішуєте, який із них вам більше до вподоби. Перший – через власність:
$el->src = 'image.jpg'; // встановлює атрибут src
echo $el->src; // 'image.jpg'
unset($el->src); // знімаємо атрибут
// або $el->src = null;
Другий спосіб – виклик методів, які, на відміну від встановлення властивостей, можна об'єднувати в ланцюжки:
$el = Html::el('img')->src('image.jpg')->alt('photo');
// <img src="image.jpg" alt="photo">
$el->alt(null); // скасування атрибута
І третій спосіб – найбільш багатослівний:
$el = Html::el('img')
->setAttribute('src', 'image.jpg')
->setAttribute('alt', 'photo');
echo $el->getAttribute('src'); // 'image.jpg'
$el->removeAttribute('alt');
Атрибути можуть бути встановлені масово за допомогою
addAttributes(array $attrs)
і видалені за допомогою
removeAttributes(array $attrNames)
.
Значення атрибута не обов'язково має бути рядком, ви також можете використовувати логічні значення для логічних атрибутів:
$checkbox = Html::el('input')->type('checkbox');
$checkbox->checked = true; // <input type="checkbox" checked>
$checkbox->checked = false; // <input type="checkbox">
Атрибут також може бути масивом значень, які виводяться через пробіли, що корисно, наприклад, для класів CSS:
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null se ignoruje
$el->class[] = 'top';
echo $el; // '<input class="active top">'
Альтернативою є асоціативний масив, де значення вказують, чи повинен ключ бути виведений:
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
Стилі CSS можуть бути записані у вигляді асоціативних полів:
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
Зараз ми використовували властивість, але те ж саме можна написати, використовуючи методи:
$el = Html::el('input');
$el->style('color', 'green');
$el->style('display', 'block');
echo $el; // '<input style="color: green; display: block">'
Або навіть у найкоротшому вигляді:
$el = Html::el('input');
$el->appendAttribute('style', 'color', 'green');
$el->appendAttribute('style', 'display', 'block');
echo $el; // '<input style="color: green; display: block">'
І остання деталь: метод href()
може полегшити складання
параметрів запиту в URL:
echo Html::el('a')->href('index.php', [
'id' => 10,
'lang' => 'en',
]);
// '<a href="index.php?id=10&lang=en"></a>'
Атрибути даних
Атрибути даних мають спеціальну підтримку. Оскільки їхні імена
містять дефіси, доступ через властивості та методи не такий
елегантний, тому існує метод data()
:
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // не так елегантно
$el->data('max-size', '500x300'); // елегантно
echo $el; // '<input data-max-size="500x300">'
Якщо значенням атрибута даних є масив, він автоматично серіалізується в JSON:
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
Зміст елемента
Встановіть внутрішній вміст елемента за допомогою методів
setHtml()
або setText()
. Використовуйте перший варіант тільки в
тому разі, якщо ви знаєте, що передаєте в параметрі надійно захищений
рядок HTML.
echo Html::el('span')->setHtml('hello<br>');
// '<span>hello<br></span>'
echo Html::el('span')->setText('10 < 20');
// '<span>10 < 20</span>'
І навпаки, для отримання внутрішнього вмісту використовуйте методи
getHtml()
або getText()
. Останній метод видаляє HTML-теги з виводу і
перетворює HTML-сутності на символи.
echo $el->getHtml(); // '10 < 20'
echo $el->getText(); // '10 < 20'
Дочірні вузли
Усередині елемента також може бути масив дочірніх вузлів. Кожен із
них може бути або рядком, або іншим елементом Html
. Вони
вставляються за допомогою addHtml()
або addText()
:
$el = Html::el('span')
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// <span>hello<br>10 < 20<br></span>
Інший спосіб створення та вставки нового вузла Html
:
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
->setText('hello');
// <ul><li class="first">hello</li></ul>
Ви можете працювати з вузлами так, як якщо б вони були масивами. Тобто,
звертайтеся до кожного з них за допомогою квадратних дужок, рахуйте їх
за допомогою count()
і виконуйте ітерації:
$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
Новий вузол може бути вставлений у певне місце за допомогою
insert(?int $index, $child, bool $replace = false)
. Якщо $replace = false
, то буде
вставлено елемент у позицію $index
і переміщено інші. Якщо це
$index = null
, то елемент додається останнім.
// вставляє елемент на першу позицію і зсуває інші
$el->insert(0, Html::el('span'));
Усі вузли витягуються за допомогою методу getChildren()
і
видаляються за допомогою методу removeChildren()
.
Створення фрагмента документа
Якщо ми хочемо працювати з масивом вузлів і нас не цікавить елемент
обгортки, ми можемо створити фрагмент документа, передавши
null
замість імені елемента:
$el = Html::el(null)
->addHtml('hello<br>')
->addText('10 < 20')
->addHtml( Html::el('br') );
// hello<br>10 < 20<br>
Методи fromHtml()
і fromText()
пропонують швидший спосіб
створення фрагмента:
$el = Html::fromHtml('hello<br>');
echo $el; // 'hello<br>'
$el = Html::fromText('10 < 20');
echo $el; // '10 < 20'
Генерування виведення HTML
Найпростіший спосіб виведення елемента HTML – використовувати
echo
або переписати об'єкт на (string)
. Ви також можете
виводити відкриваючі або закриваючі теги й атрибути окремо:
$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"'
Важливою особливістю є автоматичний захист від міжсайтового скриптингу (XSS).
Будь-які значення атрибутів або вміст, вставлений через setText()
або addText()
, надійно екранується:
echo Html::el('div')
->title('" onmouseover="bad()')
->setText('<script>bad()</script>');
// <div title='" onmouseover="bad()'><script>bad()</script></div>
HTML ↔ перетворення тексту
Для перетворення HTML у текст можна використовувати статичний метод
htmlToText()
:
echo Html::htmlToText('<span>One & Two</span>'); // 'One & Two'
HtmlStringable
Об'єкт Nette\Utils\Html
реалізує інтерфейс Nette\HtmlStringable
, який,
наприклад, Latte або Forms використовує для розрізнення об'єктів, що мають
метод __toString()
, який повертає HTML-код. Тому не буде подвійного
екранування, якщо, наприклад, ми перерахуємо об'єкт у шаблоні,
використовуючи {$el}
.