Můj web

Vlastní validátor v Zendu

Publikováno 11.4.2012

Potřebujete-li zvalidovat vstup z formuláře na více než jen formát vstupních dat, hodí se napsat si vlastní validátor. Ten pokryje další pravidla na vstupní data daná aplikační logikou. Není to až tak triviální, tím více, pokud nepoužíváte přímo čistý Zend Framework, ale například jen některé knihovny. Tady je příklad, jak na to.

Klasický příklad na kontrolu identického hesla zadaného pro kontrolu je už zastaralý. Zend nabízí pro tento příklad specifický validátor Identical. Napíšeme si tedy pro změnu validátor pro kontrolu, zda vybrané ID uživatele není náhodou stejné s přihlášeným uživatelem. Nejprve vytvoříme vlastní třídu pro validaci v souboru UserLogged.php (umístění knihovny v adresářové struktuře je jasné z názvu třídy):

class MyApp_Validate_UserLogged extends Zend_Validate_Abstract {
  const NOT_AVAILABLE = 'notAvailable';
  protected $_messageTemplates = array(
    self::NOT_AVAILABLE => 'You cannot choose logged user'
  );
  public function isValid($value, $context = null) {
    if(isset($context['userId']) &&
      ($context['userId'] != MyApp_Application::$userAuth->getId()))
      return true;
    $this->_error(self::NOT_AVAILABLE);
    return false;
  }
}

(ID přihlášeného uživatele jsme trochu magicky vytáhli ze statické proměnné, ale to teď nepitvejme.)

Validovanému elementu userId přiřadíme validátor UserLogged, například takto v config.ini:

myform.elements.userId.options.validators.userlogged.validator = "UserLogged"

A příchází závěrečná taškařice – je potřeba říct, odkud se mají brát validátory. Standardně hledá Zend knihovny s validátory (třídy) pouze v Zend/Validate/. Musíme tedy specifikovat prefix a cestu k vlastním validátorům. V kódu např. takto:

$form = new App_Form($config->myform);
$form->addElementPrefixPath('MyApp_Validate', './library/MyApp/Validate/', 'validate');

Popis metody addElementPrefixPath najdete v dokumentaci. Nespoléhejte na to, že máte nějak nastartovaný autoloader. Cesta k souborům musí být skutečně přesně zadána!

Je možné přesunout toto i do konfiguračního souboru, což mi přijde správnější:

myform.elementPrefixPath.prefix = "MyApp"
myform.elementPrefixPath.path = "./library/MyApp/"

V kódu pak vynechejte volání metody addElementPrefixPath. Jelikož nemám v konfiguraci zadaný typ „validate“, přidá si ho Zend automaticky sám. (Bohužel se mi ho tam nepodařilo podstrčit.)

Pokud byste z nějakého důvodu chtěli přidávat elementy a prefixpath mimo konstruktor, použijete konfigurační pole s klíči elements a elementPrefixPath:

$form = new App_Form(array('elementPrefixPath'=>$config->myform->elementPrefixPath->toArray()));

Elementy formuláře můžu přidat buď v konstruktoru jako další člen vstupního pole s klíčem ‚elements‘ nebo obdobně, ale později metodou addElements. Na pořadí zadání elementPrefixPath a elements nezáleží, ani když je provádíme metodami mimo konstruktor.

S výše uvedenou konfigurací prefixPath narazíte na problém, pokud přidáte do formuláře podformulář neboli subform. Zend vyhodí chybu, že nemůže přidat prefixPath do podformuláře, protože to není pole. Výše uvedená konfigurace totiž není úplně správně. Správně je potřeba přidávat prefixPath jako položky pole – máte pak možnost jich přidat více. A jelikož na konfiguraci formulářů používám formát YAML, nevím přesně, jak zadat pole ve formátu ini na potřebném místě konfigurační proměnné. Ukázka tedy bude v YAMLu:

prod:
  form_name:
    elementPrefixPath:
      -
       prefix: MyApp_Validate
       path: ./library/MyApp/Validate/
       type: validate
    elements:
      id:
        type: text
        options:
...

Teď tedy máme konečně zápis korektní o čemž svědčí i to, že se nám podařilo zadat typ pluginu prefixPath (hodnota validate).

Komentáře

Komentáře jsou vypnuty.