Lekce 2 - Tvorba formulářového frameworku v PHP - HtmlBuilder
V minulé lekci, Tvorba formulářového frameworku v PHP - Motivace, jsme si vysvětlili, že díky použití frameworku pro obsluhu formulářů budeme část aplikace programovat několikrát rychleji.
V dnešním dílu našeho tutoriálu k PHP formulářům si vytvoříme jednoduchou třídu pro renderování HTML kódu.
Motivace
MVC je sice hezká věc, ale v našich aplikacích budeme narážet i na situace, kdy potřebujeme často renderovat malé úseky HTML kódu nebo renderovat takový HTML kód, kde množství prezentační logiky překoná samotný objem HTML kódu. Použití šablon je zde možné, ale nemusí být vždy efektivní, proto budeme renderovat HTML přímo.
Udělejme si jednoduchý příklad. Budeme chtít vyrenderovat HTML kód pro
<select>
, který vypadá následovně:
<label for="znacka-vozu">Značka vozu</label> <select name="znacka-vozu" id="znacka-vozu" required="required"> <option value="skoda">Škoda</option> <option value="bmw">BMW</option> <option value="audi">Audi</option> </select>
Chtěli bychom, aby se <select>
vyrenderoval pomocí
nějaké PHP metody. Zatím si metodu představme jako statickou na nějakém
helperu, volali bychom ji takto:
<?= FormHelper::renderSelect('znacka-vozu', 'Značka vozu', true, array( 'Škoda' => 'skoda', 'BMW' => 'bmw', 'Audi' => 'audi', )) ?>
Že podobnou metodu pro práci s formuláři potřebujeme by mělo být jasné, jelikož pole možností často získáváme z databáze a se statickým HTML bychom si tedy nevystačili.
Implementace metody by mohla vypadat následovně:
<?php public static function renderSelect(string $name, string $title, bool $required, array $data) : string { $html = '<label for="' . htmlspecialchars($name) . '">' . htmlspecialchars($title) . '</label>'; $html .= '<select name="' . htmlspecialchars($name) . '" id="' . htmlspecialchars($name) . '" '; if ($required) $html .= 'required="required"'; $html .= '>'; foreach ($data as $title => $value) { $html .= '<option value="' . htmlspecialchars($value) . '">' . htmlspecialchars($title) . '</option>'; } return $html . '</select>'; }
V kódu jsem zanedbal označení vybrané položky. Kód je začátečnický
a trpí mnoha neduhy. HTML se špatně zvýrazňuje, protože je jako obyčejný
string
. Jsme odkázáni na ruční ošetřování hodnot pomocí
PHP funkce htmlspecialchars()
a vše znepřehledňuje konkatenace
řetězce do proměnné $html
.
HtmlBuilder
Třída HtmlBuilder
vychází z principu SAX, který se
používá pro zápis XML souborů. Odstiňuje nás od samotné HTML syntaxe a
generování kódu zjednodušuje na práci s jednotlivými elementy. Vnitřně
se HTML samozřejmě sestavuje podobně, jako jsme si to ukázali výše.
Výhodou však je, že zvenčí s ním pracujeme jako s elementy a ne jako s
řetězcem.
Ukažme si vyrenderování selectu pomocí třídy
HtmlBuilder
:
public static function renderSelect(string $name, string $title, bool $required, string $data) : string { $builder = new HtmlBuilder(); $builder->addValueElement('label', $title, array( 'for' => $name, )); $selectAttributes = array( 'name' => $name, 'id' => $name, ); if ($required) $selectAttributes['required'] = 'required'; $builder->startElement('select', $selectAttributes); foreach ($data as $title => $value) { $builder->addValueElement('option', $title, array( 'value' => $value, )); } $builder->endElement(); return $builder->render(); }
Pracujeme pouze s elementy a poli jejich atributů. Vše se spojuje a ošetřuje samo, máme minimum možností něco zkazit. Výsledkem je totožný HTML kód, jako na začátku článku.
Implementace
Připravme si třídu HtmlBuilder
a rovnou do ní vložme dva
privátní atributy. Bude se jednat o sestavovaný HTML řetězec a zásobník
otevřených párových elementů. Díky zásobníku víme, který element jsme
naposledy otevřeli a můžeme ho tak jednoduše uzavřít bez uvedení jeho
názvu:
class HtmlBuilder { private string $html = ''; private array $elementStack = array(); }
Třídu si samozřejmě jako vždy komentujte.
Přidejme privátní metodu k vyrenderování elementu:
private function renderElement(string $name, array $htmlParams, bool $pair) : void { $this->html .= '<' . htmlspecialchars($name); foreach ($htmlParams as $key => $value) { $this->html .= ' ' . htmlspecialchars($key) . '="' . htmlspecialchars($value) . '"'; } if (!$pair) $this->html .= ' /'; $this->html .= '>'; if ($pair) array_push($this->elementStack, $name); }
Metodě předáme název elementu, jeho HTML parametry a upřesníme, zda je párový. Metoda vytvoří jeho HTML řetězec a připojí ho do výsledného HTML. Pokud je element párový, uložíme si do zásobníku také informaci, že je otevřený.
Pomocí této privátní metody vytvoříme několik veřejných:
public function addElement(string $name, array $htmlParams = array()) : void { $this->renderElement($name, $htmlParams, false); } public function startElement(string $name, array $htmlParams = array()) : void { $this->renderElement($name, $htmlParams, true); } public function addValue(string $value, bool $doNotEscape = false) : void { $this->html .= $doNotEscape ? $value : htmlspecialchars($value); } public function endElement(string $name = '') : void { if (empty($name)) $name = array_pop($this->elementStack); $this->html .= '</' . htmlspecialchars($name) . '>'; } function addValueElement(string $name, string $value, array $htmlParams = array(), bool $doNotEscape = false) : void { $this->startElement($name, $htmlParams, true); $this->addValue($value, $doNotEscape); $this->endElement(); }
Představme si, co které metody dělají:
- Metoda
addElement()
vyrendruje jednoduchý nepárový element, startElement()
otevře párový element,addValue()
přidá HTML kód - buď do otevřeného elementu, nebo klidně mimo něj, můžeme si také zvolit, zda se má hodnota převádět na entity, či nikoli,endElement()
uzavře poslední otevřený párový element, pokud bychom chtěli uzavírat nějaký element, který otevřela např. jiná instance builderu, můžeme uvést i jméno,addValueElement()
otevře párový element, vloží do něj hodnotu a poté ho uzavře.
Výsledné HTML vrátí metoda render()
:
public function render() : string { return $this->html; }
Máme hotovo. Okomentovaná třída je ke stažení v příloze.
V příští lekci, FormControl - Předek pro formulářové kontrolky v PHP, započneme práce na třídě
FormControl
, která bude předkem pro všechny kontrolky
formuláře.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 526x (3.69 kB)
Aplikace je včetně zdrojových kódů v jazyce PHP