11. diel - Dokončenie triedy FormControl v PHP
V minulej lekcii, FormControl - Predok pre formulárové kontrolky v PHP , sme si začali práce na triede FormControl, ktorá je predkom pre všetkých formulárové kontrolky. Dnes triedu dokončíme.
Pretože sme si pridali metódu addPatternRule (), môžeme teraz v ďalších pravidlách overovať regulárne výrazy. To využijeme napr. U pravidlá pre minimálnu dĺžku hodnoty:
Pravidlo minimálnej dĺžky
public function addMinLengthRule($minLength, $validateClient = true, $validateServer = true) { return $this->addPatternRule('.{' . $minLength . ',}', $validateClient, $validateServer); }
Pravidlo heslá
Ďalej pridáme pravidlo pre validáciu hesla. Heslo bude musieť byť dlhšia ako 6 znakov, čo vyriešime pridaním pravidlá s PATTERN. Ďalej nebude smieť obsahovať diakritiku, čo overíme pre zjednodušenie až na serveri.
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 pre dátum a čas
Nakoniec pridajme trojicu metód pre pridanie pravidlá na dátum a čas, dátum samotný a samotný čas. Pre každé pravidlo pridáme opäť 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ý súbor
Metódy zakončíme pravidlom pre nahranie povinného súboru.
public function addFileRequiredRule($validateClient = true, $validateServer = true) { return $this->addRule(array( 'type' => self::RULE_REQUIRED_FILE, 'message' => 'Soubor je povinný', ), $validateClient, $validateServer); }
Pravidiel by sa samozrejme dalo vymyslieť ešte veľa, ale neskoršie kombináciou týchto som docielil zatiaľ všetkého, čo som potreboval. A keby niečo náhodou nestačilo, vždy sa dajú jednoducho pridať. Určite by sme však ich počet mali držať na absolútnom minime, pravidlá s rovnakým mechanizmom budeme z týchto ešte neskôr odvodzovať v triede Form.
Validácia
Kontrolke teda môžeme pridať niekoľko pravidiel. Teraz napíšeme tú časť triedy, ktorá bude jednotlivé pravidlá overovať. Ako už bolo povedané, budeme to robiť 2x, raz na strane klienta a raz na strane servera.
Klientská časť
Metóda nižšie pridá kontrolke HTML atribúty podľa validačných pravidiel, ktoré obsahuje. Budeme využívať atribútov HTML 5, veľmi jednoducho tak overíme regulárne výrazy, povinné polia a maximálnu dĺžku.
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žiaľ nevie viac patternov a tak sa bude overovať len prvý. Pokiaľ bude mať pole niekoľko ďalších (čo sa mi asi ešte nestalo), overí sa až na serveri.
Serverová časť
Podobný switch umiestnime aj do metódy checkRule (), ktorá overuje jedno pravidlo na serveri. Všimnite si, že používame knižnice DateUtils a StringUtils, ktoré sme si predtým vytvorili.
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; }
Ak pravidlo zlyhá, budeme chcieť, aby sa kontrolka podfarbil červeno. K tomuto účelu triede pridajme verejný atribút $ invalid:
public $invalid;
Validácia zakončíme vrcholnú metódou checkValidity (), ktorá overí všetky pravidlá a ak niektoré neplatí, nastaví invalid na true, pridá CSS triedu invalid a vyvolá výnimku:
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']); } } }
Triedu UserException budeme používať pre všetky výnimky, ktorej správa je určená pre užívateľov. Kód triedy je nasledujúci:
class UserException extends Exception { }
Rendering
Renderovanie (generovanie HTML kódu pre kontrolku) budeme realizovať abstraktné metódou, ktorú si každá konkrétna kontrolka implementuje po svojom. Zároveň však budeme chcieť, aby sa tesne po zavolaní renderovanie pridali kontrolke klientskej validačný parametre. Z toho dôvodu necháme metódu potomka ako protected a zavoláme ju z verejnej render ():
protected abstract function renderControl($isPostBack); public function render($validateClient, $isPostBack) { if ($validateClient) $this->addClientParams(); return $this->renderControl($isPostBack); }
Načítanie a uloženie dát
Zostáva ešte dodať nejaké rozhranie pre ukladanie a načítanie dát z / do kontrolky. Budeme rovno počítať s tým, že kontrolka môže obsahovať viac hodnôt a nie len jednu. Môžeme tak realizovať napr. Checklist, čo je kontrolka, obsahujúci niekoľko checkbox. Výhodou viac polí v jednej kontrolke je ľahšie tvorba formulára.
Dodajme metódu getData (), ktorá vráti dáta v kontrolke. Ak bola nejaká hodnota odoslaná na server (v $ _POST je kľúč s názvom kontrolky), tak vráti tú, inak nevráti nič. Aby sme zachovali koncept vracania viac hodnôt, vrátime vždy pole. Kontrolky s viacerými políčkami si túto metódy potom prepíšu, tým klasickým bude postačovať.
public function getData() { return isset($_POST[$this->name]) ? array($this->name => $_POST[$this->name]) : array(); }
Podobne urobme metódu, ktorá vracia kľúče všetkých polí v kontrolke:
public function getKeys() { return array($this->name); }
Funkcia na nastavenie hodnoty bude už závisieť na potomkovi a preto ju len predpíšeme ako abstraktný:
public abstract function setData($key, $value);
Tým máme základ kontroliek hotový. Nabudúce, v lekcii Formulárový framework v PHP - InputBox , si napíšeme prvú kontrolku, ktorú bude InputBox. Hotová a zdokumentovaná trieda FormControl je k stiahnutiu v prílohe.
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 449x (2.83 kB)
Aplikácia je vrátane zdrojových kódov v jazyku php