Vytvoření vlastního typu pole

Krom připravených typů formulářových polí si můžete samozřejmě vytvořit své vlastní pole – vlastní typ, nebo lepší implementaci pro již existující typ. Jedinou podmínkou je použití dědičnosti. Každé formulářové pole (respektive jeho třída) musí dědit od třídy Jet\Form_Field. Vaše třídy tedy musí dědit od uvedené třídy, ale samozřejmě mohou dědit od libovolné již existující třídy. Prostě standardní objektově orientované programování ❤️

Pozor na jednu důležitou věc. Pokud používáte automatické generování formulářů mapovaných na třídy a chcete vaši novou třídu (nebo celý nový typ) použít i pro tyto formuláře, tak musíte dát vědět příslušné továrně, že existuje nový typ, nebo že daný existující typ pole reprezentuje nová třída.

Nová implementace existujícího typu formulářového pole

Jak bylo řečeno, tak stačí vytvořit novou třídu, která může dědit od stávající třídy reprezentující daný typ formulářového pole: namespace JetApplication;

use 
Jet\Form;
use 
Jet\Form_Field_Tel;

class 
MyForm_Field_Tel extends Form_Field_Tel {
    
//.. ... ..    
}
POZOR! Je nutné předat informaci továrně. Volání továren je nutné umístit do inicializace aplikace. Tedy do skriptu ~/application/Init/Factory.php: use Jet\Factory_Form;

Factory_Form::setFieldClassName( Form::TYPE_TEL, MyForm_Field_Tel::class );

Zcela nový typ pole

Nyní pojďme vytvořit novou třídu a především úplně nový typ pole. Třída může mít implementované vlastní metody pro zachytávání a validaci (a případně libovolné další metody). Důležité je, že její vlastnost $_type musí informovat o tom, jaký typ formulářového pole představuje. S touto informací se totiž bude operovat i dále. Je dobré si pro typ vytvořit novou konstantu. Zde je pro ukázku použita imaginární konstanta MyForm::MY_NEW_FIELD_TYPE.

Dále je nutné pole napojit na InputCatcher a Validator. Samozřejmě můžete buď vybrat jeden z připravených zachytávačů vstupu a validátorů, nebo si rovněž vytvořit vlastní.

namespace JetApplication;

use 
Jet\Form;
use 
Jet\Form_Field;
use 
Jet\Data_Array;

class 
MyForm_Field_NewType extends Form_Field
{
    
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    
protected string $_type = MyForm::MY_NEW_FIELD_TYPE;
    protected 
string $_validator_type = Validator::TYPE_INT;
    protected 
string $_input_catcher_type = InputCatcher::TYPE_INT;
    
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!    
}

Třídu tedy máme. Ale ještě je nutné udělat několik věcí:

  • Zaregistrovat nový typ / novou třídu do továrny formuláře (jinak by typ nemohl být použit například pro automaticky generované formuláře).
  • Zaregistrovat, jaké renderery budou pro nový typ pole použity.
  • Zaregistrovat, jaké view skripty budou pro daný typ použity.

Registrace typu do továrny

Registraci typu do továrny provedeme takto: use Jet\Factory_Form;

Factory_Form::setFieldClassName( MyForm::MY_NEW_FIELD_TYPE, MyForm_Field_NewType::class );

POZOR! Volání továren je nutné umístit do inicializace aplikace. Tedy do skriptu ~/application/Init/Factory.php.

Registrace rendererů

Nyní je nutné továrně říct, jaké renderery budou pro nový typ pole použity.

Opět budeme pracovat s továrnou, tedy ve skriptu ~/application/Init/Factory.php

Kompletní volání může mít tuto podobu: Factory_Form::setRendererFieldClassName( MyForm::MY_NEW_FIELD_TYPE, 'field', Form_Renderer_Field::class );
Factory_Form::setRendererFieldClassName( MyForm::MY_NEW_FIELD_TYPE, 'container', Form_Renderer_Field_Container::class );
Factory_Form::setRendererFieldClassName( MyForm::MY_NEW_FIELD_TYPE, 'error', Form_Renderer_Field_Error::class );
Factory_Form::setRendererFieldClassName( MyForm::MY_NEW_FIELD_TYPE, 'help', Form_Renderer_Field_Help::class );
Factory_Form::setRendererFieldClassName( MyForm::MY_NEW_FIELD_TYPE, 'input', Form_Renderer_Field_Input_Common::class );
Factory_Form::setRendererFieldClassName( MyForm::MY_NEW_FIELD_TYPE, 'label', Form_Renderer_Field_Label::class );
Factory_Form::setRendererFieldClassName( MyForm::MY_NEW_FIELD_TYPE, 'row', Form_Renderer_Field_Row::class );
Uff ... To je ale poněkud zdlouhavé volání. Ovšem je dobré si jej pro představu a úplnost ukázat.

Ukažme si ale praktičtější volání, které nahradí vše, co jsme si do teď ukázali, a provede vše potřebné. Factory_Form::registerNewFieldType(
    
field_type: MyForm::MY_NEW_FIELD_TYPE,
    
field_class_name: MyForm_Field_NewType::class,
    
renderers: [
        
'input' => MyForm_Renderer_Field_Input_Special::class
    ] 
);
Tento kus kódu provede vše potřebné – takto se reálně a jednoduše registruje nový typ. Jiná volání nejsou nutná! Tato metoda zaregistruje třídu i renderery pro nový typ. Všimněte si prosím, že v seznamu elementů a rendererů je uveden pouze element input. Pokud chcete pro ostatní elementy použít výchozí renderery, tak není nutné je uvádět a budou doplněny výchozí hodnoty.

Záměrně jsme si ukázali oba způsoby, i když praktičtější je určitě ten druhý.

Registrace view skriptů

Poslední, co nám zbývá, je říct systému, jaké výchozí view skripty bude nový typ pole mít. To musíme dát vědět systémové konfiguraci.

Pro pořádek je dobré udělat to také ve skriptu ~/application/Init/Factory.php

Princip je stejný jako u registrace rendererů a také je možné použít volání několika metod pro každé view zvlášť, ale tím vás již zde trápit nebudu a rovnou si ukažme optimální způsob, jak to udělat: SysConf_Jet_Form_DefaultViews::registerNewFieldType(
    
field_type: MyForm::MY_NEW_FIELD_TYPE,
    
views: [
        
'input' => 'field/input/my-special',
        
'label' => 'field/label-my-special'
    
]
);
Jak je vidět, tak ani zde není nutné vyjmenovávat všechna view, ale pouze ta, která chcete mít nastavena jinak, než jsou výchozí hodnoty systému.

Tedy celá registrace nového typu má ve finále tuto podobu: namespace JetApplication;

use 
Jet\Factory_Form;
use 
Jet\SysConf_Jet_Form_DefaultViews;

Factory_Form::registerNewFieldType(
    
field_type: MyForm::MY_NEW_FIELD_TYPE,
    
field_class_name: MyForm_Field_NewType::class,
    
renderers: [
        
'input' => MyForm_Renderer_Field_Input_Special::class
    ]
);

SysConf_Jet_Form_DefaultViews::registerNewFieldType(
    
field_type: MyForm::MY_NEW_FIELD_TYPE,
    
views: [
        
'input' => 'field/input/my-special'
    
]
);

Nový parametr vašeho formulářového pole

Obecný princip vytvoření nového typu pole již znáte, ale vraťme se ještě jednou na začátek. Uvedený příklad zatím počítal pouze s tím, že budete mít vlastní implementaci zachycení dat a validace.

Ale to u složitějších typů polí zdaleka nemusí stačit. V reálném světě budete potřebovat, aby nový typ pole měl i své parametry. Podobně jako u číselných typů lze určit rozmezí od–do, u souborů povolené typy nahrávaných souborů a tak dále. Viz typy formulářových polí.

V podstatě je to jednoduché. Prostě přidáte třídě představující typ formulářového pole potřebnou vlastnost, getter a setter a pochopitelně implementujete logiku použití daného parametru – zejména při validaci. Ano, takto to stačí a bude to fungovat.

Ovšem pokud jste si již zkoušeli Jet Studio, tak jste nalezli nástroj na mapování formulářů na třídy. A pokud budete chtít, aby tento nástroj znal i váš nový typ formulářového pole, tak jej musíte správně zaregistrovat. Ale nejen to, musíte i definovat parametry vašeho nového pole. Tak aby například Jet Studio poznalo, že se jedná o parametr formuláře, a umělo s ním pracovat (tedy aby bylo možné „naklikávat“ i váš nový vstupní element).

Jak to udělat? Dát vlastnosti, která představuje nový parametr, příslušné atributy. Rovnou si ukažme reálný příklad přímo z Jet. Tento trait se používá pro číselná formulářová pole, kde může figurovat rozsah platných číselných hodnot: namespace Jet;

trait 
Form_Field_Part_NumberRangeInt_Trait
{
    
    #[
Form_Definition_FieldOption(
        
type: Form_Definition_FieldOption::TYPE_INT,
        
label: 'Minimal value',
        
getter: 'getMinValue',
        
setter: 'setMinValue',
    )]
    protected ?
int $min_value = null;
    
    #[
Form_Definition_FieldOption(
        
type: Form_Definition_FieldOption::TYPE_INT,
        
label: 'Maximal value',
        
getter: 'getMaxValue',
        
setter: 'setMaxValue',
    )]
    protected ?
int $max_value = null;
    
    #[
Form_Definition_FieldOption(
        
type: Form_Definition_FieldOption::TYPE_INT,
        
label: 'Step',
        
getter: 'getStep',
        
setter: 'setStep',
    )]
    protected ?
int $step = null;

    
// ... ... ...
}

Jak vidíte, tak k definici slouží atributy a je to poměrně triviální definice.

Ovšem podle těchto parametrů je nutné nastavit například validátor. To se provádí přetížením metody getValidator takto:

public function getValidator() : Validator
    
{
        if(!
$this->validator) {
            
$this->validator = $this->validatorFactory();
        }
        
        
/**
         * @var Validator_Int $validator
         */
        
$validator = $this->validator;
        
$validator->setMinValue( $this->getMinValue() );
        
$validator->setMaxValue( $this->getMaxValue() );
        
        return 
$validator;
    }


Parametry definice

Parametr Význam
type O jaký typ se jedná.
Seznam typů viz dále.
label Popis parametru. Popis je určen pro nástroj jako je Jet Studio.
setter Název metody – setteru v rámci třídy představující formulářové pole, pomocí kterého lze parametr nastavit.
getter Název metody – getteru v rámci třídy představující formulářové pole, pomocí kterého lze zjistit nastavenou hodnotu parametru.

Typy parametrů

Typ Význam
Form_Definition_FieldOption::TYPE_STRING Hodnota typu string
Form_Definition_FieldOption::TYPE_INT Hodnota typu int
Form_Definition_FieldOption::TYPE_FLOAT Hodnota typu float
Form_Definition_FieldOption::TYPE_BOOL Hodnota typu bool
Form_Definition_FieldOption::TYPE_CALLABLE Volání – fakticky pole o dvou pozicích. První pozice (index 0) může být:
  • self::class
    jedná se pak o statické volání sebe sama.
  • řetězec 'this'
    jedná se o volání sebe sama přes $this.
  • Konkrétní název třídy (buď jako řetězec, nebo jako NameSpace\Class::class).
Form_Definition_FieldOption::TYPE_ARRAY Prosté pole.
Form_Definition_FieldOption::TYPE_ASSOC_ARRAY Asociativní pole.
Předchozí kapitola
Jet\Form_Definition_SubForms
Další kapitola
Jet\Form_Definition_FieldOption