Nette\Utils\Html – pomocník kodéra

před 17 lety od David Grudl  

Malá třída pro generování bezpečného HTML kódu v PHP.

Způsobů, jak v PHP vygenerovat kód stránky, je celá řada. Od obyčejného volání příkazu echo, přes použití šablon, až po funkce DOM. Hledání nejlepší metody vede k paradoxu. Čím je programátor zkušenější, tím více tíhne k čistějším řešením, ideálně na bázi XML DOM. Tím však začne narážet na nové překážky a omezení a více času tráví jejich řešením a obcházením. Díky čemuž více tíhne k pragmatickým řešením, jako je třeba volání echo.

Ale posuzování vhodnosti jednotlivých způsobů není předmětem článku.

Seznamte se s Nette\Utils\Html

Generování HTML značek „na koleně“ vede k nepřehlednému kódu a tím i k větší náchylnosti k chybám. Vezměme si jednoduchý příklad:

echo '<select name="person"',
	($required ? ' class="required"' : ''), '>';
$res = dibi::query('SELECT * FROM [persons] WHERE [group]=%s', $group);
while ($rec = $res->fetch())
	echo '<option value="', $rec['id'], '"',
		($active == $rec['id'] ? ' selected="selected"' : ''),
		'>', htmlSpecialChars($rec['name']),
		'</option>';

echo '</select>';

Nic moc, že? Zápis lze značně zpřehlednit za použití Nette\Utils\Html pomocníka. Jde o malou knihovničku, která má za úkol objektově zapouzdřit HTML elementy a především nabídnout programátorovi intuitivní a šikovné rozhraní.

Nejprve malá ochutnávka:

use Nette\Utils\Html;

// vytvoříme element
$el = Html::el('img');

// nastavíme atributy
$el->src = 'image.gif';
$el->alt = $text;

// a vypíšeme ho
echo $el; // <img src="image.gif" alt="...">

Atributy lze nastavovat i voláním přetížených metod, například $el->src('image.gif'). Zde lze s výhodou využít řetězovitého volání (fluent interfaces):

$params['id'] = 10;
echo Html::el('a')->href('http://www.dgx.cz', $params)->setText('Klikněte');
// vypíše <a href="http://www.dgx.cz?id=10">Klikněte</a>

echo Html::el('img')->src($url)->alt($alt);

echo Html::el('input')->type($secret ? 'password' : 'text');

Atributem však nemusí být jen řetězec:

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

// atribut zrušíme hodnotou null
$el->type = null;	// <input />

// lze použít dokonce pole
$el->class[] = $active ? 'active' : null; // null se ignoruje
$el->class[] = 'top';

$el->style['color'] = 'green';
$el->style['display'] = 'block';

echo $el;
// <input class="active top" style="color: green; display: block" />

Někdy dávám přednost samostatnému vypsání počáteční a koncové značky namísto celého elementu:

$el = Html::el('div');
echo $el->startTag();
...
... nyní vypisujeme obsah
...
echo $el->endTag();

// nebo obsah rovnou nastavíme elementu
$el->setText('Barnes & Noble');
echo $el; // <div>Barnes &amp; Noble</div>

// nebo HTML kód
$el->setHtml('Barnes &amp; Noble');
echo $el; // <div>Barnes &amp; Noble</div>

Děti a vnoučata

Rodina je základ HTML státu a proto i každý uzel Nette\Utils\Html může mít své potomky:

$el = Html::el();
// všimněte si, $el je nyní "kontejner", tj. bez názvu elementu

// a vytvoříme potomka, element strong
$strong = $el->create('strong');
$strong->setText('La Trine');
// nebo lze psát rovnou:
// $el->create('strong', 'La Trine');

// lze přidávat existující uzly Html
$br = Html::el('br');
$el->add($br);

echo $el; //  <strong>La Trine</strong><br />

// uzel může být i textový
$el->add('Yes!'); // obdoba setText

// k potomkům lze přistupovat přímo přes ArrayAccess
$el[] = 'Hello!';

if ($el->count()) ...

A zpět k příkladu

Nakonec přepíši úvodní příklad do přehlednější formy pomocí Nette\Utils\Html:

$el = Html::el('select')->name('person')->class($required ? 'required' : null)

$res = dibi::query('SELECT * FROM [persons] WHERE [group]=%s', $group);
while ($rec = $res->fetch())
	$el->create('option')
		->value($rec['id'])
		->selected($active == $rec['id'])
		->setText($rec['name']);

echo $el;