11. díl - Dokončení třídy FormControl v PHP

PHP Knihovny Dokončení třídy FormControl v PHP American English version English version

V minulém dílu našeho seriálu tutoriálu o tvorbě PHP knihoven jsme si započali práce na třídě FormControl, která je předkem pro všechny formulářové kontrolky. Dnes třídu dokončíme.

Protože jsme si přidali metodu addPatternRule(), můžeme nyní v dalších pravidlech ověřovat regulární výrazy. To využijeme např. u pravidla pro minimální délku hodnoty:

Pravidlo minimální délky
public function addMinLengthRule($minLength, $validateClient = true, $validateServer = true)
{
        return $this->addPatternRule('.{' . $minLength . ',}', $validateClient, $validateServer);
}
Pravidlo hesla

Dále přidáme pravidlo pro validaci hesla. Heslo bude muset být delší než 6 znaků, což vyřešíme přidáním pravidla s patternem. Dále nebude smět obsahovat diakritiku, což ověříme pro zjednodušení až na serveru.

public function addPasswordRule($validateClient = true, $validateServer = true)
{
        $this->addMinLengthRule(6, $validateClient);
        return $this->addRule(array(
                'type' => self::RULE_PASSWORD,
                'message' => 'Heslo nesmí obsahovat diakritiku a musí být dlouhé alespoň 6 znaků.',
        ), $validateClient, $validateServer);
}
Pravidlo pro datum a čas

Nakonec přidejme trojici metod pro přidání pravidla na datum a čas, samotné datum a samotný čas. Pro každé pravidlo přidáme opět pattern.

public function addDateTimeRule($validateClient = true, $validateServer = true)
{
        $this->addPatternRule('[0-3]?[0-9]\.[0-1]?[0-9]\.[0-9]{4}\s[0-2]?[0-9]\:[0-5]?[0-9](\:[0-5]?[0-9])?');
        return $this->addRule(array(
                'type' => self::RULE_DATETIME,
                'format' => DateUtils::DATETIME_FORMAT,
                'message' => 'Hodnota musí být ve formátu: dd.mm.yyyy hh:mm(:ss)',
        ), $validateClient, $validateServer);
}

public function addDateRule($validateClient = true, $validateServer = true)
{
        $this->addPatternRule('[0-3]?[0-9]\.[0-1]?[0-9]\.[0-9]{4}');
        return $this->addRule(array(
                'type' => self::RULE_DATETIME,
                'format' => DateUtils::DATE_FORMAT,
                'message' => 'Hodnota musí být ve formátu: dd.mm.yyyy',
        ), $validateClient, $validateServer);
}

public function addTimeRule($validateClient = true, $validateServer = true)
{
        $this->addPatternRule('[0-2]?[0-9]\:[0-5]?[0-9](\:[0-5]?[0-9])?');
        return $this->addRule(array(
                'type' => self::RULE_DATETIME,
                'format' => DateUtils::TIME_FORMAT,
                'message' => 'Hodnota musí být ve formátu: hh:mm(:ss)',
        ), $validateClient, $validateServer);
}

Povinný soubor

Metody zakončeme pravidlem pro nahrání povinného souboru.

public function addFileRequiredRule($validateClient = true, $validateServer = true)
{
        return $this->addRule(array(
                'type' => self::RULE_REQUIRED_FILE,
                'message' => 'Soubor je povinný',
        ), $validateClient, $validateServer);
}

Pravidel by se samozřejmě dalo vymyslet ještě spoustu, ale pozdější kombinací těchto jsem docílil zatím všeho, co jsem potřeboval. A kdyby něco náhodou nestačilo, vždy se dají jednoduše přidat. Určitě bychom však jejich počet měli držet na absolutním minimu, pravidla se stejným mechanismem budeme z těchto ještě později odvozovat ve třídě Form.

Validace

Kontrolce tedy můžeme přidat několik pravidel. Nyní napíšeme tu část třídy, která bude jednotlivá pravidla ověřovat. Jak již bylo řečeno, budeme to dělat 2x, jednou na straně klienta a jednou na straně serveru.

Klientská část

Metoda níže přidá kontrolce HTML atributy podle validačních pravidel, které obsahuje. Budeme využívat atributů HTML 5, velmi jednoduše tak ověříme regulární výrazy, povinná pole a maximální délku.

public function addClientParams()
{
        foreach ($this->rules as $rule)
        {
                if ($rule['validate_client'])
                {
                        switch ($rule['type'])
                        {
                                case self::RULE_REQUIRED:
                                case self::RULE_REQUIRED_FILE:
                                        $this->htmlParams['required'] = 'required';
                                        break;
                                case self::RULE_MAX_LENGTH:
                                        $this->htmlParams['maxlength'] = $rule['max_length'];
                                        break;
                                case self::RULE_PATTERN:
                                        if (!isset($this->htmlParams['pattern']))
                                                $this->htmlParams['pattern'] = $rule['pattern'];
                                        break;
                        }
                }
        }
}

HTML 5 bohužel neumí více patternů a tak se bude ověřovat jen první. Pokud bude mít pole několik dalších (což se mi asi ještě nestalo), ověří se až na serveru.

Serverová část

Podobný switch umístíme i do metody checkRule(), která ověřuje jedno pravidlo na serveru. Všimněte si, že používáme knihovny DateUtils a StringUtils, které jsme si předtím vytvořili.

private function checkRule($rule)
{
        $name = $this->name;
        switch ($rule['type'])
        {
                case self::RULE_REQUIRED:
                        return isset($_POST[$name]) && (is_numeric($_POST[$name]) || !empty($_POST[$name]));
                case self::RULE_MAX_LENGTH:
                        return !isset($_POST[$name]) || !$_POST[$name] || mb_strlen($_POST[$name]) <= $rule['max_length'];
                case self::RULE_PATTERN:
                        return !isset($_POST[$name]) || !$_POST[$name] || preg_match('~^' . $rule['pattern'] . '$~u', $_POST[$name]);
                case self::RULE_REQUIRED_FILE:
                        return isset($_FILES[$name]) && isset($_FILES[$name]['name']) && $_FILES[$name]['name'];
                case self::RULE_DATETIME:
                        return !isset($_POST[$name]) || !$_POST[$name] || DateUtils::validDate($_POST[$name], $rule['format']);
                case self::RULE_PASSWORD:
                        return !isset($_POST[$name]) || !$_POST[$name] || ((StringUtils::removeAccents($_POST[$name]) == $_POST[$name]) && (mb_strlen($_POST[$name]) >= 6));
        }
        return false;
}

Pokud některé pravidlo selže, budeme chtít, aby se kontrolka podbarvila červeně. K tomuto účelu třídě přidejme veřejný atribut $invalid:

public $invalid;

Validace zakončeme vrcholnou metodou checkValidity(), která ověří všechna pravidla a pokud některé neplatí, nastaví invalid na true, přidá CSS třídu invalid a vyvolá výjimku:

public function checkValidity()
{
        foreach ($this->rules as $rule)
        {
                if (($rule['validate_server']) && (!$this->checkRule($rule)))
                {
                        $this->invalid = true;
                        $this->addClass('invalid');
                        throw new UserException($rule['message']);
                }
        }
}

Třídu UserException budeme používat pro všechny výjimky, jejíž zpráva je určená pro uživatele. Kód třídy je následující:

class UserException extends Exception
{

}

Rendering

Renderování (generování HTML kódu pro kontrolku) budeme realizovat abstraktní metodou, kterou si každá konkrétní kontrolka implementuje po svém. Zároveň však budeme chtít, aby se těsně po zavolání renderování přidaly kontrolce klientské validační parametry. Z toho důvodu necháme metodu potomka jako protected a zavoláme ji z veřejné render():

protected abstract function renderControl($isPostBack);

public function render($validateClient, $isPostBack)
{
        if ($validateClient)
                $this->addClientParams();
        return $this->renderControl($isPostBack);
}

Načtení a uložení dat

Zbývá ještě dodat nějaké rozhraní pro ukládání a načítání dat z/do kontrolky. Budeme rovnou počítat s tím, že kontrolka může obsahovat více hodnot a ne jen jednu. Můžeme tak realizovat např. CheckList, což je kontrolka, obsahující několik CheckBoxů. Výhodou více polí v jedné kontrolce je snadnější tvorba formuláře.

Dodejme metodu getData(), která vrátí data v kontrolce. Pokud byla nějaká hodnota odeslaná na server (v $_POST je klíč s názvem kontrolky), tak vrátí tu, jinak nevrátí nic. Abychom zachovali koncept vracení více hodnot, vrátíme vždy pole. Kontrolky s více políčky si tuto metody potom přepíší, těm klasickým bude postačovat.

public function getData()
{
        return isset($_POST[$this->name]) ? array($this->name => $_POST[$this->name]) : array();
}

Podobně udělejme metodu, která vrací klíče všech polí v kontrolce:

public function getKeys()
{
        return array($this->name);
}

Funkce pro nastavení hodnoty bude již záviset na potomkovi a proto ji jen předepíšeme jako abstraktní:

public abstract function setData($key, $value);

Tím máme základ kontrolek hotový. Příště si napíšeme první kontrolku, kterou bude InputBox. Hotová a zdokumentovaná třída FormControl je ke stažení v příloze.


 

Stáhnout

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

 

  Aktivity (1)

Č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 (5 hlasů) :
55555


 



 

 

Komentáře

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.

Zatím nikdo nevložil komentář - buď první!