Lekce 3 - FormControl - Předek pro formulářové kontrolky v PHP
V minulé lekci, Tvorba formulářového frameworku v PHP - HtmlBuilder, jsme si vytvořili HTML builder pro snadné generování krátkých úseků HTML.
V dnešním dílu našeho PHP tutoriálu vytvoříme abstraktní třídu
FormControl
, která sloužit jako předek pro
konkrétní kontrolky formuláře (např. pro TextBox
).
Deklarace třídy
FormControl
Jak již bylo řečeno, třída FormControl
bude předkem pro
všechny formulářové prvky. Bude obsahovat zejména mechanismus
validací a několik společných vlastností a metod, aby se s
kontrolkami mohlo pracovat pomocí stejného rozhraní.
Připravme si tedy prázdnou třídu:
abstract class FormControl { }
Společné vlastnosti
Začněme jednoduše. Každá kontrolka bude mít nějaký název, popisek a HTML atributy. Do třídy tyto vlastnosti přidáme a napíšeme pro ně konstruktor:
public string $label; public array $htmlParams = array(); public string $name; public function __construct(string $name, string $label = '', array $htmlParams = array()) { $this->name = $name; $this->label = $label; $this->htmlParams = $htmlParams; $this->htmlParams['name'] = $name; $this->htmlParams['id'] = $name; }
Jméno a ID kontrolky rovnou nastavíme do HTML parametrů. To jsou HTML atributy, které se k elementu při renderování (převodu do HTML kódu) přidají.
Setter pro ToolTip
Když jsme u těch jednoduchých vlastností, přidejme ještě setter na
vlastnost ToolTip
. To je text, který se zobrazí když na
kontrolku najedete myší, stačí ho jen nastavit do HTML atributu
title
. Typicky obsahuje nápovědu, co do pole zadat:
public function setTooltip(string $toolTip) : FormControl { $this->htmlParams['title'] = $toolTip; return $this; }
Gettery a settery se v PHP oproti např. Javě příliš nepoužívají. V
tomto případě však hrají důležitou úlohu. Setter vrací instanci
FormControl
, budou to tak dělat všechny settery. Když budeme
kontrolkám nastavovat nějaké vlastnosti, museli bychom to bez setterů
udělat následujícím stylem:
$jmenoBox = $form->addTextBox('jmeno', 'Jméno', true); $jmenoBox->toolTip = 'Zadejte své celé jméno'; $jmenoBox->text = 'Jan Novák';
Díky tomu, že settery vrací instanci, na které je metoda volána, můžeme na ni zas zavolat další metodu, a tak je krásně řetězit. Kód výše můžeme tedy zapsat takto:
$form->addTextBox('jmeno', 'Jméno', true) ->setToolTip('Zadejte své celé jméno') ->setText('Jan Novák');
Jistě uznáte, že tato varianta je mnohem čitelnější. Protože definice formulářů budou ještě obsáhlejší, tak na kompaktnosti kódu velmi záleží.
Přiřazení CSS třídy
Přidejme kontrolce ještě metodu, která k ní přiřadí nějakou CSS třídu. Musíme počítat i s tím, že již nějakou má:
public function addClass(string $class) : void { if (isset($this->htmlParams['class'])) $this->htmlParams['class'] .= ' ' . $class; else $this->htmlParams['class'] = $class; }
Nastavení validace
Přejděme k validační části třídy, která je bezesporu tou nejdůležitější.
Validační pravidla
Validace formulářových polí budeme realizovat tak, že bude možné
každému poli přidat několik validačních pravidel. Proto přidáme kolekci
$rules
:
private array $rules = array();
Jednotlivá pravidla budou např. pravidlo povinného pole, pravidlo regulárního výrazu, pravidlo pro heslo a podobně. Po odeslání formuláře se každé kontrolce ověří její pravidla a to jak na klientovi, tak na serveru.
Jednotlivá pravidla nebo validátory, chcete-li, jsem se rozhodl realizovat
přímo uvnitř třídy FormControl
pomocí jednoduchých metod.
Mohli bychom také oddělit každé pravidlo do samostatné třídy, ale v
našem případě bychom získali velmi jednoduché a podobné třídy. Dosáhli
bychom tak, podle mého názoru, příliš vysoké granularity kódu. Druhý
přístup jsem naopak zvolil dále u konkrétních kontrolek formuláře.
Výčet pravidel
Jednotlivá pravidla si uložíme výčtového typu (enum
).
Přidáme si šest položek:
enum Rules { case Required; case MaxLength; case Password; case DateTime; case Pattern; case RequiredFile; }
Podle názvu jistě poznáte, co které pravidlo ověřuje. Další pravidla lze sestavit různými kombinacemi.
Přidávání pravidel
Každé pravidlo bude reprezentované jako asociativní pole. K jejich
přidání do kolekce $rules
si vytvoříme privátní metodu:
private function addRule(array $rule, bool $validateClient, bool $validateServer) : FormControl { $rule['validate_client'] = $validateClient; $rule['validate_server'] = $validateServer; $this->rules[] = $rule; return $this; }
Metoda bere pole, které obsahuje data pravidla. Další dva parametry označují, zda se má pravidlo kontrolovat na klientovi a na serveru. Pravidlu přidáme tyto vlastnosti podle parametrů a uložíme ho do kolekce. Za účelem dodržení přístupu setterů vrátíme instanci.
Pravidlo povinného pole
Přidejme metodu, která kontrolce přidá pravidlo povinného pole:
public function addRequiredRule(bool $validateClient = true, bool $validateServer = true) : FormControl { return $this->addRule(array( 'type' => Rule::Required, 'message' => 'Povinné pole', ), $validateClient, $validateServer); }
Metoda vyrobí pole s pravidlem. Každé pravidlo bude vždy obsahovat klíč
type
s typem pravidla a poté klíč message
s
chybovou hláškou. Ta se zobrazí v případě, že pravidlo nebude splněno.
Metoda addRequiredRule()
tedy zobrazí message
, pokud
je pole nevyplněné nebo úplně chybí. Pravidlo přidáme pomocí privátní
metody addRule()
do kolekce $rules
.
Stejným způsobem vytvoříme další metody pro přidání pravidel dalších typů.
Pravidlo maximální délky
Pravidlo maximální délky se později na klientovi přeloží na atribut
maxlength
. Bude vypadat následovně:
public function addMaxLengthRule(int $maxLength, bool $validateClient = true, bool $validateServer = true) : FormControl { return $this->addRule(array( 'type' => Rule::MaxLength, 'max_length' => $maxLength, 'message' => 'Maximální délka hodnoty je ' . $maxLength, ), $validateClient, $validateServer); }
Pravidlo pro regulární výraz
Naprosto klíčové pro nás bude pravidlo, které ověří hodnotu pole regulárním výrazem:
public function addPatternRule(string $pattern, bool $validateClient = true, bool $validateServer = true) : FormControl { return $this->addRule(array( 'type' => Rule::Pattern, 'pattern' => $pattern, 'message' => 'Hodnota má nesprávný formát', ), $validateClient, $validateServer); }
Validaci regulárním výrazem budeme hojně používat v dalších pravidlech. Do třídy si přidáme několik konstant pro ty nejpoužívanější:
const PATTERN_URL = '(http|https)://.*'; const PATTERN_INTEGER = '[0-9]+'; const PATTERN_EMAIL = '[a-z0-9._-]+@[a-z0-9.-]+\.[a-z]{2,4}';
Pravidla budeme psát bez stříšky na začátku a dolaru na konci
(^
a $
), přidají se tam později automaticky.
V příští lekci, Dokončení třídy FormControl v PHP, přidáme do třídy FormControl
další metody pro pravidla a také metody pro jejich vyhodnocení.