Definice formulářů
Jak jsme si řekli v předchozí kapitole, tak formuláře je nutné definovat a je jedno zda se chystáme formulář použít pouze pro zachycení a validaci dat, nebo i pro zobrazení. Základní definice je vždy společná.
Princip definice je vlastně naprosto triviální. Formulář je reprezentován instancí třídy Jet\Form. Formulářové pole je obecně reprezentováno abstraktní třídou Jet\Form_Field, ovšem vždy má konkrétní typ formulářového pole (tedy i konkrétní účel, vlastnosti a celkové chování formulářového pole), který je reprezentován jednou ze tříd. Přehled typů polí a jejich tříd najdete zde. Toto je obecný princip, ale pojďme si k tomu říct několik detailů.
Vytvoření instance pole
Pro vytvoření pole jsou dvě možnosti. Buď tradiční vytvoření instance:
use Jet\Form;
use Jet\Form_Field_FileImage;
$img_field = new Form_Field_FileImage(
name: 'image',
label: 'Image:',
is_required: true
);
$img_field->setMaximalFileSize( 2048 );
$img_field->setMaximalSize( maximal_width: 800, maximal_height: 600 );
Nebo prostřednictvím příslušné továrny:
use Jet\Form;
use Jet\Form_Field;
use Jet\Form_Field_FileImage;
use Jet\Factory_Form;
/**
* @var Form_Field_FileImage $img_field
*/
$img_field = Factory_Form::getFieldInstance(
type: Form_Field::TYPE_FILE_IMAGE,
name: 'image',
label: 'Image',
is_required: true
);
$img_field->setMaximalFileSize( 2048 );
$img_field->setMaximalSize( maximal_width: 800, maximal_height: 600 );
V ukázkové aplikaci můžete vidět, že v rámci aplikačního prostoru je používán klasický přístup přímého použití názvu třídu a naopak uvnitř knihovny Jet (tedy v adresáři ~/library/Jet) jsou striktně používány továrny. Kdysi jsme používal továrny i v aplikačním prostoru pro zachování konzistence, ale to se ukázalo jako nepraktické a tak trochu otravné.
Smyslem továren je snadné nahrazení tříd bez zásahů do jádra celé platformy. Tedy musíte mít možnost třeba třídu Jet\Form_Field_Tel nahradit svou vlastní třídou a to i když často používáte automatické generování formulářů pomocí mapování na třídy. Tam jsou továrny prostě nezbytné.
Ovšem v aplikačním prostoru máte vše pod kontrolou a je jen na vás jakou instanci čeho vytvoříte a případná výměna třídy za jinou není v dobách moderních IDE problém - je to práce pár okamžiků. Tedy z toho důvodu platí, že vnitřně Jet pro vytváření formulářů používá továrnu, ale v aplikačním prostoru (včetně mikroaplikací jako je například instalátor) se vytváří z důvodu praktičnosti instance přímo.
Název pole
Proč se zabývat názvem formulářového pole? Jedna důležitá specialita tu je. Například pro psaní tohoto textu potřebuji v redakčním systému tohoto webu například tyto pole:
<input type="text" name="content[cs_CZ-initial][title]">
<textarea name="content[cs_CZ-initial][annotation]"></textarea>
<textarea name="content[cs_CZ-initial][description]"></textarea>
<textarea name="content[cs_CZ-initial][key_words]"></textarea>
<textarea name="content[cs_CZ-initial][text]"></textarea>
Teď si na chvíli představme, že nejsme v Jet aplikaci, ale je použito čisté PHP a já chci z požadavku získat český text tohoto článku. Udělám to takto:
$text = $_POST['content'][$locale.'-'.$version]['text'];
Prostě a jednoduše řečeno: S formuláři a jejich daty potřebujeme operovat jako s N rozměrným polem.
Ovšem jak již asi víte, tak v Jet aplikaci se k superglobálním polím $_GET a $_POST ani nedostanete (v běžném nastavení) a pokud už by bylo teoreticky nutné "sahat" na POST přímo (což při práci s formuláři nutné není a je to nežádoucí - ale pro názornost to udělejme), tak lze data získáme takto:
$text = Http_Request::POST()->getString('/content/'.$locale.'-'.$version.'/text');
Jak vidíte, tak k datům v poli se přistupuje pomocí cesty. Je to univerzální přístup, který se v Jet používá všude a vychází ze základní třídy Jet\Data_Array.
A asi nikoho nepřekvapí, že zcela totožným způsobem bude pojmenováno formulářové pole v definici. Tedy:
foreach( Application_Web::getBase()->getLocales() as $locale ) {
//*******************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
$text_field = new Form_Field_Textarea('/content/'.$locale.'-'.$version.'/text', 'Text:');
//*******************************************!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
$text_field->setDefaultValue( $this->getContent($locale)->getText() );
$text_field->setFieldValueCatcher( function( $value ) use ($locale, $version) {
$this->getContent($locale)->setText( $value );
});
//... ... ...
$form->addField( $text_field );
}
Poznámka: V ukázce trochu předbíhám téma a je tam rovnou kázáno i zachycení dat (předání hodnoty nějaké instanci). O tom si víc povíme v extra kapitole. Ale když už jsem zde pro demonstraci ukázal ne zcela ideální přístup, tak jsem musel rovnou ukázat i ten správný ;-)
Přidávání pole do formuláře
Formulářový prvek musí být v nějakém formuláři a formulář potřebuje formulářové prvky. To dá rozum. Ale i zde si ukážeme pár zajímavých možností.
Přidání polí rovnou
Základní a asi nejčastější možnost je přidání polí do formuláře rovnou při vytvoření jeho instance:
use Jet\Form;
use Jet\Form_Field_Input;
use Jet\Form_Field_Tel;
$name_field = new Form_Field_Input('name', 'Name:');
$tel_number_field = new Form_Field_Tel('tel_number', 'Tel. number:');
$form = new Form( name:'contact_form', fields: [
$name_field,
$tel_number_field
]);
Přidání polí do existujícího formuláře
Z různých důvodů můžeme potřebovat přidat pole do již existujícího formuláře. Například může jít o formulář vytvořený rodičovskou třídou, který si v potomkovi potřebujeme upravit a tak dále. Možností je celá řada.
use Jet\Form;
use Jet\Form_Field_Input;
use Jet\Form_Field_Tel;
//... ... ...
$name_field = new Form_Field_Input('name', 'Name:');
$tel_number_field = new Form_Field_Tel('tel_number', 'Tel. number:');
$form->addField( $name_field );
$form->addField( $tel_number_field );
Dokonce je možné dělat takové věci, jako vzít pole z formuláře prvního, to přejmenovat a umístit jej do formuláře druhého:
$clone_field = clone $form_a->field('some_field');
$clone_field->setName('new_name');
$form_b->addField( $clone_field );
Odebírání pole
Není to častá situace, ale v praxi narazíte na situaci, kdy je naopak nutné / vhodné pole z formuláře odstranit. I tato možnost samozřejmě existuje:
$form->removeField( 'some_field' );
Název formuláře
Jak jste si již jistě všimli v příkladech, tak nejen pole, ale i formulář samotný má své jméno:
use Jet\Form;
$form = new Form( name:'some_form_name', fields: [
//... ... ...
]);
K čemu je to dobré? Pokud na stránce budete mít více jak jeden formulář, tak musí být jasné který formulář je právě odeslán a tedy má být zachycen a zpracován. Název formuláře se pak používá jako hodnota skrytého pole. Název tohoto speciálního skrytého pole lze samozřejmě změnit a to buď globálně pro celou aplikaci, nebo pro každý formulář zvlášť. Výchozí název tohoto pole je: _jet_form_sent_.
Pozor! I když formulář název mít musí, tak existence skrytého pole s názvem formuláře není podmínkou. Ostatně pro takové REST API, kde jsou formuláře také používány pro zachycení a validaci, by to bylo dosti nešťastné. Formulář lze zachytit i bez tohoto pole, ale to si ukážeme v jiné kapitole.
Kam dál?
Teď už znáte obecný princip definice formuláře. Ovšem než se pustíte do zajímavé problematicky zachytávání a validace formulářů stejně tak jako jejich zobrazování, tak doporučuji kouknout na referenci k třídy Jet\Form a také se prosím seznamte s třídou Jet\Form_Field a typy formulářových polí.