9. díl - Tvorba formulářového frameworku v PHP - HtmlBuilder

PHP Knihovny Tvorba formulářového frameworku v PHP - HtmlBuilder American English version English version

V minulém dílu našeho seriálu tutoriálu o tvorbě PHP knihoven jsme si vysvětlili, že díky použití frameworku pro obsluhu formulářů budeme tuto část aplikace programovat několikrát rychleji. V dnešním dílu si vytvoříme jednoduchou třídičku 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 selectu, 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 asi 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($name, $title, $required, $data)
{
        $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í HtmlBuilderu:

public static function renderSelect($name, $title, $required, $data)
{
        $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 s tím 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 $html = '';
        private $elementStack = array();

}

Třídu si samozřejmě jako vždy komentujte. Přidejme privátní metodu k vyrenderování elementu:

private function renderElement($name, $htmlParams, $pair)
{
        $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 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 že je otevřený.

Pomocí této privátní metody vytvoříme několik veřejných:

public function addElement($name, $htmlParams = array())
{
        $this->renderElement($name, $htmlParams, false);
}

public function startElement($name, $htmlParams = array())
{
        $this->renderElement($name, $htmlParams, true);
}

public function addValue($value, $doNotEscape = false)
{
        $this->html .= $doNotEscape ? $value : htmlspecialchars($value);
}

public function endElement($name = null)
{
        if (!$name)
                $name = array_pop($this->elementStack);
        $this->html .= '</' . htmlspecialchars($name) . '>';
}

function addValueElement($name, $value, $htmlParams = array(), $doNotEscape = false)
{
        $this->startElement($name, $htmlParams, true);
        $this->addValue($value, $doNotEscape);
        $this->endElement();
}

Představme si, co které metody dělají:

  • addElement() vyrendruje jednoduchý nepárový element.
  • startElement() otevře párový element.
  • addValue() přidá HTML kód a to buď do otevřeného elementu nebo klidně mimo něj. Můžeme si zvolit, zda se má hodnota převádět na entity či nikoli.
  • endElement() uzavře poslední otevřený párový element. Můžeme uvést i jméno v případě, že bychom chtěli uzavírat nějaký element, který otevřela např. jiná instance builderu.
  • 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()
{
        return $this->html;
}

Máme hotovo. Okomentovaná třída je ke stažení v příloze. Příště započneme práce na předkovi pro kontrolky formuláře.


 

Stáhnout

Staženo 285x (3.43 kB)
Aplikace je včetně zdrojových kódů v jazyce php

 

  Aktivity (2)

Článek pro vás napsal David Čápka
Avatar
Autor pracuje jako softwarový architekt a pedagog na projektu ITnetwork.cz (a jeho zahraničních verzích). Velmi si váží svobody podnikání v naší zemi a věří, že když se člověk neštítí práce, tak dokáže úplně cokoli.
Unicorn College Autor se informační technologie naučil na Unicorn College - prestižní soukromé vysoké škole IT a ekonomie.

Jak se ti líbí článek?
Celkem (10 hlasů) :
4.64.64.64.64.6


 



 

 

Komentáře

Avatar
rosatislav
Člen
Avatar
rosatislav:

Zdravím, chtěl bych se zeptat proč u funkce *

function addValueElement($name, $value, $htmlParams = array(), $doNotEscape = false)
{
        $this->startElement($name, $htmlParams, true);
        $this->addValue($value, $doNotEscape);
        $this->endElement();
}
  • dáváte funkci startElement ještě navíc "true", když se do ní mají dát jen hodnoty "$name a $htmlParams "
Editováno 19.5.2014 21:08
 
Odpovědět 19.5.2014 21:07
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 1 zpráv z 1.