Nette Documentation Preview

syntax
HTML елементи
*************

.[perex]
Клас [api:Nette\Utils\Html] є помічником для генерації HTML-коду, який запобігає виникненню вразливості Cross Site Scripting (XSS).


Він працює так, що його об'єкти представляють HTML-елементи, яким ми встановлюємо параметри та дозволяємо їх відобразити:

```php
$el = Html::el('img');  // створює елемент <img>
$el->src = 'image.jpg'; // встановлює атрибут src
echo $el;               // виводить '<img src="image.jpg">'
```

Встановлення:

```shell
composer require nette/utils
```

Усі приклади передбачають створений псевдонім:

```php
use Nette\Utils\Html;
```


Створення HTML-елемента
=======================

Елемент створюємо методом `Html::el()`:

```php
$el = Html::el('img'); // створює елемент <img>
```

Крім назви, ви можете вказати й інші атрибути в HTML-синтаксисі:

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

Або передати їх як асоціативний масив другим параметром:

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

Зміна та повернення назви елемента:

```php
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true, оскільки <img> є порожнім елементом
```


HTML атрибути
=============

Окремі HTML-атрибути ми можемо змінювати та читати трьома способами, залежно від того, який вам більше сподобається. Перший з них — через властивості:

```php
$el->src = 'image.jpg'; // встановлює атрибут src

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

unset($el->src);  // скасовує атрибут
// або $el->src = null;
```

Другий шлях — виклик методів, які, на відміну від встановлення властивостей, можна ланцюжком викликати один за одним:

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

$el->alt(null); // скасування атрибута
```

А третій спосіб — найбільш багатослівний:

```php
$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)`.

Значенням атрибута не обов'язково має бути рядок, можна використовувати й логічні значення для логічних атрибутів:

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

Атрибутом може бути й масив значень, які будуть виведені, розділені пробілами, що зручно, наприклад, для CSS-класів:

```php
$el = Html::el('input');
$el->class[] = 'active';
$el->class[] = null; // null ігнорується
$el->class[] = 'top';
echo $el; // '<input class="active top">'
```

Альтернативою є асоціативний масив, де значення вказують, чи має бути виведений ключ:

```php
$el = Html::el('input');
$el->class['active'] = true;
$el->class['top'] = false;
echo $el; // '<input class="active">'
```

CSS-стилі можна записувати у формі асоціативних масивів:

```php
$el = Html::el('input');
$el->style['color'] = 'green';
$el->style['display'] = 'block';
echo $el; // '<input style="color: green; display: block">'
```

Зараз ми використовували властивості, але те саме можна записати за допомогою методів:

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

Або навіть найбільш багатослівним способом:

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

Ще одна дрібниця на завершення: метод `href()` може полегшити складання параметрів запиту в URL:

```php
echo Html::el('a')->href('index.php', [
	'id' => 10,
	'lang' => 'en',
]);
// '<a href="index.php?id=10&amp;lang=en"></a>'
```


Data атрибути
-------------

Спеціальну підтримку мають data-атрибути. Оскільки їхні назви містять дефіси, доступ через властивості та методи не такий елегантний, тому існує метод `data()`:

```php
$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // не так елегантно
$el->data('max-size', '500x300'); // елегантно
echo $el; // '<input data-max-size="500x300">'
```

Якщо значенням data-атрибута є масив, він автоматично серіалізується в JSON:

```php
$el = Html::el('input');
$el->data('items', [1,2,3]);
echo $el; // '<input data-items="[1,2,3]">'
```


Вміст елемента
==============

Внутрішній вміст елемента встановлюємо методами `setHtml()` чи `setText()`. Перший з них використовуйте лише в тому випадку, якщо ви знаєте, що в параметрі передаєте надійно безпечний HTML-рядок.

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

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

І навпаки, внутрішній вміст отримуємо методами `getHtml()` чи `getText()`. Другий з них видаляє з виводу HTML-теги та перетворює HTML-сутності на символи.

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


Дочірні вузли
-------------

Внутрішній вміст елемента може бути також масивом дочірніх (children) вузлів. Кожен з них може бути або рядком, або іншим `Html` елементом. Вставляємо їх за допомогою `addHtml()` чи `addText()`:

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

Інший спосіб для створення та вставки нового `Html` вузла:

```php
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
	->setText('перший');
// <ul><li class="first">перший</li></ul>
```

З вузлами можна працювати так само, якби це був масив. Тобто звертатися до окремих з них за допомогою квадратних дужок, підраховувати їх за допомогою `count()` та ітерувати по них:

```php
$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`, додасть елемент в кінець.

```php
// вставити елемент на першу позицію та зсунути інші
$el->insert(0, Html::el('span'));
```

Усі вузли отримуємо методом `getChildren()` та видаляємо їх методом `removeChildren()`.


Створення фрагмента документа
-----------------------------

Якщо ми хочемо працювати з масивом вузлів і нас не цікавить обгортаючий елемент, ми можемо створити так званий *document fragment*, передавши `null` замість імені елемента:

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

Швидший спосіб створення фрагмента пропонують методи `fromHtml()` та `fromText()`:

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

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


Генерація HTML-виводу
=====================

Найпростішим способом вивести HTML-елемент є використання `echo` або перетворення об'єкта на `(string)`. Можна також окремо вивести відкриваючі або закриваючі теги та атрибути:

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

Важливою рисою є автоматичний захист від [Cross Site Scripting (XSS) |nette:glossary#Cross-Site Scripting XSS]. Усі значення атрибутів або вміст, вставлений через `setText()` чи `addText()`, надійно екрануються:

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

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


Перетворення HTML ↔ текст
=========================

Для перетворення HTML на текст ви можете використати статичний метод `htmlToText()`:

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


HtmlStringable
==============

Об'єкт `Nette\Utils\Html` реалізує інтерфейс `Nette\HtmlStringable`, за допомогою якого, наприклад, Latte або форми розрізняють об'єкти, що мають метод `__toString()`, який повертає HTML-код. Таким чином, не відбувається подвійного екранування, якщо, наприклад, ми виводимо об'єкт у шаблоні за допомогою `{$el}`.

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 ігнорується
$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&amp;lang=en"></a>'

Data атрибути

Спеціальну підтримку мають data-атрибути. Оскільки їхні назви містять дефіси, доступ через властивості та методи не такий елегантний, тому існує метод data():

$el = Html::el('input');
$el->{'data-max-size'} = '500x300'; // не так елегантно
$el->data('max-size', '500x300'); // елегантно
echo $el; // '<input data-max-size="500x300">'

Якщо значенням data-атрибута є масив, він автоматично серіалізується в 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 &lt; 20</span>'

І навпаки, внутрішній вміст отримуємо методами getHtml() чи getText(). Другий з них видаляє з виводу HTML-теги та перетворює HTML-сутності на символи.

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

Дочірні вузли

Внутрішній вміст елемента може бути також масивом дочірніх (children) вузлів. Кожен з них може бути або рядком, або іншим Html елементом. Вставляємо їх за допомогою addHtml() чи addText():

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

Інший спосіб для створення та вставки нового Html вузла:

$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
	->setText('перший');
// <ul><li class="first">перший</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().

Створення фрагмента документа

Якщо ми хочемо працювати з масивом вузлів і нас не цікавить обгортаючий елемент, ми можемо створити так званий document fragment, передавши null замість імені елемента:

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

Швидший спосіб створення фрагмента пропонують методи fromHtml() та fromText():

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

$el = Html::fromText('10 < 20');
echo $el; // '10 &lt; 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"'

Важливою рисою є автоматичний захист від Cross Site Scripting (XSS). Усі значення атрибутів або вміст, вставлений через setText() чи addText(), надійно екрануються:

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

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

Перетворення HTML ↔ текст

Для перетворення HTML на текст ви можете використати статичний метод htmlToText():

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

HtmlStringable

Об'єкт Nette\Utils\Html реалізує інтерфейс Nette\HtmlStringable, за допомогою якого, наприклад, Latte або форми розрізняють об'єкти, що мають метод __toString(), який повертає HTML-код. Таким чином, не відбувається подвійного екранування, якщо, наприклад, ми виводимо об'єкт у шаблоні за допомогою {$el}.