Własny walidator w Zend Framework

Dzisiaj będzie coś dla wiel­bi­cieli Zend Frame­worka. A dokład­niej coś, z czym mamy do czynie­nia prze­twa­rza­jąc jaki­kol­wiek formu­larz, czyli wali­da­tory. Wali­da­cja, a więc spraw­dza­nie czy wpro­wa­dzone przez użyt­kow­nika dane odpo­wia­dają pewnemu sche­ma­towi jest obok filtra­cji, czyli wyrzu­ca­niu zbędnych/niebezpiecznych rzeczy z danych chyba najważ­niej­szą sprawą przy tworze­niu witryn WWW.

Zend Frame­work dyspo­nuje zesta­wem kilku­dzie­się­ciu wali­da­to­rów, które można łączyć w łańcu­chy przy wali­do­wa­niu poszcze­gól­nych pól formu­la­rza, np. pyta­jąc o wiek użyt­kow­nika pole musi zawie­rać wyłącz­nie liczby, czyli aż prosi się o Zend_Validate_Digits, a następ­nie należy spraw­dzić czy podana liczba znaj­duje się w jakimś ludz­kim prze­dziale, tzn. powiedzmy pomię­dzy 1 a 100, co zała­twi za nas Zend_Validate_Between.

Co w przy­padku jeżeli musimy dopa­so­wy­wać coś, czego nie prze­wi­dzieli twórcy ZF? Możemy napi­sać własny walidator.

Każdy wali­da­tor musi imple­men­to­wać inter­fejs Zend_Validate_Interface, czyli dwie publiczne metody:

  • isValid($value) — zwra­ca­jąca buliona prawda/fałsz
  • getMessages() — zwra­ca­jąca tablicę komu­ni­ka­tów co jest nie tak z warto­ścią testo­waną w isVa­lid(). Komu­ni­katy zwra­cane są w postaci kod_błędu => komunikat_w_ludzkiej_formie

W celu unik­nię­cia babra­nia się obsługą błędów i komu­ni­ka­tów twórcy ZF stwo­rzyli abstrak­cyjną klasę Zend_Validate_Abstract, która zrobi za nas więk­szość brud­nej roboty. Pozo­sta­nie nam tylko napi­sa­nie właści­wej logiki co ma być spraw­dzane i ewen­tu­al­nie jaki błąd zgłaszany.

Na potrzeby swojej apli­ka­cji napi­sa­łem własny w miarę uniwer­salny wali­da­tor, który spraw­dzi czy klucz podsta­wowy danej tablicy istnieje. Może mieć zasto­so­wa­nie jeżeli ktoś spraw­dza czy np. iden­ty­fi­ka­tor wybra­nej przez użyt­kow­nika kate­go­rii istnieje w bazie.

Poni­żej przed­sta­wiem kod z obja­śnie­niami po co coś jest. Po prze­czy­ta­niu stwier­dzi­cie, że pisa­nie wali­da­to­rów to fajna zabawa :-)

<?php
// rozszerzamy klasę abstrakcyjną dla walidatorów
class Spiechu_Validators_IsIdExists extends Zend_Validate_Abstract {     
 
  // definiujemy kody błędów i jakieś wartości dla nich
  const IDNOTEXISTS = 'idnotexists';
  const EMPTYSTRING = 'emptystring';
  const NULLVALUE = 'nullvalue';
 
  // definiujemy tablicę komunikatów błędów dla poszczególnych kodów
  // zwracam uwagę na '%value', które może być w locie zamienione na sprawdzaną wartość
  protected $_messageTemplates = array(
    self::IDNOTEXISTS   => "id '%value%' not exists",
    self::EMPTYSTRING  => 'given value is empty',
    self::NULLVALUE     => 'given value is null'
  );
 
  // zmienna typu Zend_Db_Table_Abstract, której klucz będziemy testować
  protected $_table;
 
  public function __construct(Zend_Db_Table_Abstract $table) {
    $this->_table = $table;
  }
 
  public function isValid($value) {
 
    // sprawdzamy czy zmienna nie jest nulem, a jeżeli tak to ustawiamy błąd
    if ($value === null) {
      $this->_error(self::NULLVALUE);
      return false;
    }
 
    // to samo dla pustego stringa
    if ($value === '') {
      $this->_error(self::EMPTYSTRING);
      return false;
    }
 
    $value = (int) $value;
 
    // ustawiamy wartość dla ewentualnego komunikatu %value%
    $this->_setValue($value);
 
    // metoda find szuka po kluczu podstawowym i zwraca rowset wyników
    $foundRows = $this->_table->find($value);
 
    // jeżeli nic nie znaleziono tzn. że sprawdzany klucz nie istenieje w tabeli bazy
    if (count($foundRows) == 0) {
      $this->_error(self::IDNOTEXISTS);
      return false;
    }
    else {
      return true;
    }
  }
}

Wszystko działa na tyle auto­ma­gicz­nie, że tworząc jakiś element formu­la­rza wystar­czy dodać stwo­rzony wali­da­tor np. tak:

$formElement = new Zend_Form_Element_Select('pole_formularza');
$formElement->setRequired(true)
  ->setLabel('Jakaś etykieta')
  ->setMultiOptions($dane_do_wyboru)
  ->addValidator(new Spiechu_Validators_IsIdExists(new Sprawdzana_Tabela()));

Podobne wpisy:

  1. Zend Frame­work i podświe­tla­nie wybra­nego elementu menu
  2. Łącze­nie zapy­tań Zend_Db_Select w Zend Frame­work [cz. 2/2]
  3. Zend_Date i Zend_Config w Zend Framework
  4. Łącze­nie zapy­tań Zend_Db_Select w Zend Frame­work [cz. 1/2]

5 Comments

  • starach
    6 grudnia 2010 - 12:13 | Permalink

    Jestem chory… „zwra­ca­jąca buliona prawda/fałsz” na prawdę ten bulion mnie rozba­wił. ;) Wiem że to skrajne leni­stwo, ale mogłeś jesz­cze wrzu­cić kod abstrak­cyjne klasy wali­da­tora. Dzięki za przy­stępne opisa­nie tematu.

  • aku
    9 grudnia 2010 - 22:22 | Permalink

    Akurat ten typ wali­da­tora jest dostępny stan­dar­dowo w ZF jako Zend_Validate_Db_NoRecordExists :) Ale arty­kuł na pewno pomocny…

  • Śpiechu
    10 grudnia 2010 - 09:16 | Permalink

    @aku:
    Zgadza się. Mój wali­da­tor jest prost­szy, szuka jedy­nie po kluczu głów­nym tabeli. Wymie­niony przez Ciebie szuka po czym chcemy, ale mimo wszystko trzeba trochę więcej konfi­gu­ro­wać, np. znać nazwę pola po którym szukamy poda­jąc argu­ment ‚field’. Moje szuka samo :-)

  • Ja
    15 lutego 2011 - 09:53 | Permalink

    Nie napi­sa­łeś gdzie umie­ścić klasę z vali­da­to­rem, w jakim pliku/katalogu

  • Śpiechu
    16 lutego 2011 - 08:34 | Permalink

    @Ja
    W Zendzie jest tak, że nazwy klas mówią gdzie szukać danego pliku. Moja klasa wali­da­tora nazywa się Spiechu_Validators_IsIdExists, a więc pliku należy szukać w kata­logu Spiechu/Validators/IsIdExists.php. Gdzie go umie­ścić? Ja trzy­mam takie rzeczy w kata­logu libra­ries obok kata­logu Zend.

  • Dodaj komentarz

    Twój adres e-mail nie zostanie opublikowany.

    Możesz użyć następujących tagów oraz atrybutów HTML-a: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <p> <pre lang="" line="" escaped=""> <q cite=""> <strike> <strong>