Nette Documentation Preview

syntax
HTML 要素
********

.[perex]
[api:Nette\Utils\Html] クラスは、HTML のコードを生成するための補助であり、クロスサイトスクリプティング(XSS)脆弱性を防ぐ助けになります。


その働き方は、オブジェクトが HTML の要素を表し、パラメータを設定してから出力するというものです。

```php
$el = Html::el('img');  // <img> 要素を作ります
$el->src = 'image.jpg'; // src 属性を設定します
echo $el;               // '<img src="image.jpg">' を出力します
```

要素の中身は `add()` メソッドでテキストやほかの要素で埋められます。テキストは自動的にエスケープされ、要素はそのまま挿入されます。 .{data-version:4.1.5}

```php
echo Html::el('div')->add(
	'Hello ',
	Html::el('b')->setText('world'),
);
// '<div>Hello <b>world</b></div>'
```

インストール:

```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"');
```

あるいは第 2 パラメータに連想配列として渡します。

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

要素の名前を変えたり取得したりするには次のようにします。

```php
$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true。<img> は空要素なので
```


HTML 属性
=========

個々の HTML 属性は 3 通りの方法で設定・取得でき、どれを好むかはあなた次第です。ひとつめはプロパティを使う方法です。

```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); // 属性を削除します
```

そして 3 つめが最も冗長な方法です。

```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'
```


子ノード
-----

要素の内側の内容は、子ノードの配列にもできます。各子は文字列でも、別の `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>
```

`add()` メソッドは複数の子を一度に挿入します。文字列は `addText()` と同じくエスケープされ、`Html` オブジェクトはそのまま挿入され、`null` の値は飛ばされるので条件つきの内容に便利です。確実に安全な HTML の文字列は `Html::html()` で包んでください。 .{data-version:4.1.5}

```php
$el = Html::el('span')->add(
	'10 < 20',
	Html::el('br'),
	Html::html('hello<br>'),
	$showNote ? Html::el('small')->setText('note') : null,
);
// <span>10 &lt; 20<br>hello<br><small>note</small></span>
```

新しい `Html` ノードを作って挿入するもうひとつの方法です。

```php
$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
	->setText('first');
// <ul><li class="first">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()` メソッドで削除できます。


ドキュメントフラグメントの作成
--------------------

一連のノードを扱いたいけれど、それを包む要素は要らないという場合は、*ドキュメントフラグメント*を作れます。これは自分自身のタグを持たず、子だけを出力します。`fragment()` メソッドはそれを作り、`add()` と同じ規則に従って一度の呼び出しで子を詰めます。 .{data-version:4.1.5}

```php
echo Html::fragment(
	Html::el('strong')->setText('hello'),
	'10 < 20',
	Html::el('br'),
);
// <strong>hello</strong>10 &lt; 20<br>
```

テキストだけ、あるいは HTML だけの内容を持つフラグメントは、`text()` と `html()` メソッドで作れます。 .{data-version:4.1.5}

```php
echo Html::text('10 < 20');   // '10 &lt; 20'
echo Html::html('hello<br>'); // 'hello<br>'
```

4.1.5 より前のバージョンにも対応する必要があるなら、要素名の代わりに `null` を渡してフラグメントを作り、`addHtml()` と `addText()` で埋めてください。`text()` と `html()` の代わりに、これらのバージョンには `fromText()` と `fromHtml()` メソッドがあります。まだ動きますが非推奨です。

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

echo Html::fromText('10 < 20');   // '10 &lt; 20'
echo Html::fromHtml('hello<br>'); // 'hello<br>'
```


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

`render(?int $indent = null)` メソッドは見やすい整形出力を提供します。インデントの水準を渡すと、出力が複数行にきれいにインデントされます。

```php
echo $el->render(0); // インデントされた HTML を返します
```

重要な機能として、[クロスサイトスクリプティング(XSS) |nette:glossary#Cross-Site Scripting (XSS)]に対する自動的な保護があります。すべての属性の値と、`setText()`、`addText()`、`add()`、`fragment()` で挿入された内容は確実にエスケープされます。

```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 や Forms は、このインターフェースを使って、HTML のコードを返す `__toString()` メソッドを持つオブジェクトを見分けます。おかげで、たとえばテンプレートで `{$el}` としてオブジェクトを出力しても二重にエスケープされません。

HTML 要素

Nette\Utils\Html クラスは、HTML のコードを生成するための補助であり、クロスサイトスクリプティング(XSS)脆弱性を防ぐ助けになります。

その働き方は、オブジェクトが HTML の要素を表し、パラメータを設定してから出力するというものです。

$el = Html::el('img');  // <img> 要素を作ります
$el->src = 'image.jpg'; // src 属性を設定します
echo $el;               // '<img src="image.jpg">' を出力します

要素の中身は add() メソッドでテキストやほかの要素で埋められます。テキストは自動的にエスケープされ、要素はそのまま挿入されます。

echo Html::el('div')->add(
	'Hello ',
	Html::el('b')->setText('world'),
);
// '<div>Hello <b>world</b></div>'

インストール:

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"');

あるいは第 2 パラメータに連想配列として渡します。

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

要素の名前を変えたり取得したりするには次のようにします。

$el->setName('img');
$el->getName(); // 'img'
$el->isEmpty(); // true。<img> は空要素なので

HTML 属性

個々の HTML 属性は 3 通りの方法で設定・取得でき、どれを好むかはあなた次第です。ひとつめはプロパティを使う方法です。

$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); // 属性を削除します

そして 3 つめが最も冗長な方法です。

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

子ノード

要素の内側の内容は、子ノードの配列にもできます。各子は文字列でも、別の 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>

add() メソッドは複数の子を一度に挿入します。文字列は addText() と同じくエスケープされ、Html オブジェクトはそのまま挿入され、null の値は飛ばされるので条件つきの内容に便利です。確実に安全な HTML の文字列は 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 &lt; 20<br>hello<br><small>note</small></span>

新しい Html ノードを作って挿入するもうひとつの方法です。

$ul = Html::el('ul');
$ul->create('li', ['class' => 'first'])
	->setText('first');
// <ul><li class="first">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() メソッドで削除できます。

ドキュメントフラグメントの作成

一連のノードを扱いたいけれど、それを包む要素は要らないという場合は、ドキュメントフラグメントを作れます。これは自分自身のタグを持たず、子だけを出力します。fragment() メソッドはそれを作り、add() と同じ規則に従って一度の呼び出しで子を詰めます。

echo Html::fragment(
	Html::el('strong')->setText('hello'),
	'10 < 20',
	Html::el('br'),
);
// <strong>hello</strong>10 &lt; 20<br>

テキストだけ、あるいは HTML だけの内容を持つフラグメントは、text()html() メソッドで作れます。

echo Html::text('10 < 20');   // '10 &lt; 20'
echo Html::html('hello<br>'); // 'hello<br>'

4.1.5 より前のバージョンにも対応する必要があるなら、要素名の代わりに null を渡してフラグメントを作り、addHtml()addText() で埋めてください。text()html() の代わりに、これらのバージョンには fromText()fromHtml() メソッドがあります。まだ動きますが非推奨です。

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

echo Html::fromText('10 < 20');   // '10 &lt; 20'
echo Html::fromHtml('hello<br>'); // 'hello<br>'

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

render(?int $indent = null) メソッドは見やすい整形出力を提供します。インデントの水準を渡すと、出力が複数行にきれいにインデントされます。

echo $el->render(0); // インデントされた HTML を返します

重要な機能として、クロスサイトスクリプティング(XSS)に対する自動的な保護があります。すべての属性の値と、setText()addText()add()fragment() で挿入された内容は確実にエスケープされます。

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 や Forms は、このインターフェースを使って、HTML のコードを返す __toString() メソッドを持つオブジェクトを見分けます。おかげで、たとえばテンプレートで {$el} としてオブジェクトを出力しても二重にエスケープされません。